diff --git a/core/lib/Drupal/Core/Cache/ApcuBackend.php b/core/lib/Drupal/Core/Cache/ApcuBackend.php
index 50fb0fd..5fa5e1a 100644
--- a/core/lib/Drupal/Core/Cache/ApcuBackend.php
+++ b/core/lib/Drupal/Core/Cache/ApcuBackend.php
@@ -208,9 +208,12 @@ public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANEN
     // until the next cache clear, restart, etc. This is what we want to do
     // when $expire equals CacheBackendInterface::CACHE_PERMANENT.
     if ($expire === CacheBackendInterface::CACHE_PERMANENT) {
-      $expire = 0;
+      $ttl = 0;
     }
-    apc_store($this->getApcuKey($cid), $cache, $expire);
+    else {
+      $ttl = max(1, $expire - REQUEST_TIME);
+    }
+    apc_store($this->getApcuKey($cid), $cache, $ttl);
   }
 
   /**
@@ -240,7 +243,7 @@ public function deleteMultiple(array $cids) {
    * {@inheritdoc}
    */
   public function deleteAll() {
-    apc_delete(new \APCIterator('user', '/^' . preg_quote($this->binPrefix, '/') . '/'));
+    apc_delete($this->getAll());
   }
 
   /**
@@ -268,8 +271,12 @@ public function invalidate($cid) {
    * {@inheritdoc}
    */
   public function invalidateMultiple(array $cids) {
-    foreach ($this->getMultiple($cids) as $cache) {
-      $this->set($cache->cid, $cache, REQUEST_TIME - 1);
+    $result = apc_fetch(array_map(array($this, 'getApcuKey'), $cids));
+    if ($result) {
+      foreach ($result as $key => $cache) {
+        $cache->expire = REQUEST_TIME - 1;
+        apc_store($key, $cache, 1);
+      }
     }
   }
 
@@ -278,8 +285,8 @@ public function invalidateMultiple(array $cids) {
    */
   public function invalidateAll() {
     foreach ($this->getAll() as $data) {
-      $cid = str_replace($this->binPrefix, '', $data['key']);
-      $this->set($cid, $data['value'], REQUEST_TIME - 1);
+      $data['value']->expire = REQUEST_TIME - 1;
+      apc_store($data['key'], $data['value'], 1);
     }
   }
 
@@ -288,10 +295,12 @@ public function invalidateAll() {
    */
   public function deleteTags(array $tags) {
     foreach ($tags as $tag) {
-      apc_inc($this->deletionsTagsPrefix . $tag, 1, $success);
+      $tag_key = $this->deletionsTagsPrefix . $tag;
+      apc_inc($tag_key, 1, $success);
       if (!$success) {
-        apc_store($this->deletionsTagsPrefix . $tag, 1);
+        apc_store($tag_key, 1);
       }
+      unset(static::$tagCache['deletions'][$tag_key]);
     }
   }
 
@@ -300,10 +309,12 @@ public function deleteTags(array $tags) {
    */
   public function invalidateTags(array $tags) {
     foreach ($tags as $tag) {
-      apc_inc($this->invalidationsTagsPrefix . $tag, 1, $success);
+      $tag_key = $this->invalidationsTagsPrefix . $tag;
+      apc_inc($tag_key, 1, $success);
       if (!$success) {
-        apc_store($this->invalidationsTagsPrefix . $tag, 1);
+        apc_store($tag_key, 1);
       }
+      unset(static::$tagCache['invalidations'][$tag_key]);
     }
   }
 
@@ -322,11 +333,12 @@ protected function checksumTags(array $tags) {
 
     foreach ($tags as $tag) {
       foreach (array('deletions', 'invalidations') as $type) {
-        if (isset(static::$tagCache[$type][$tag])) {
-          $checksum[$type] += static::$tagCache[$type][$tag];
+        $tag_key = $this->{$type . 'TagsPrefix'} . $tag;
+        if (isset(static::$tagCache[$type][$tag_key])) {
+          $checksum[$type] += static::$tagCache[$type][$tag_key];
         }
         else {
-          $query_tags[$type][] = $this->{$type . 'TagsPrefix'} . $tag;
+          $query_tags[$type][] = $tag_key;
         }
       }
     }
diff --git a/core/lib/Drupal/Core/Cache/PhpBackend.php b/core/lib/Drupal/Core/Cache/PhpBackend.php
index e188ffb..538d6d0 100644
--- a/core/lib/Drupal/Core/Cache/PhpBackend.php
+++ b/core/lib/Drupal/Core/Cache/PhpBackend.php
@@ -165,7 +165,7 @@ public function deleteMultiple(array $cids) {
    */
   public function deleteTags(array $tags) {
     foreach ($this->storage()->listAll() as $cidhash) {
-      $item = $this->getByHash($cidhash);
+      $item = $this->getByHash($cidhash, TRUE);
       if (is_object($item) && array_intersect($tags, $item->tags)) {
         $this->delete($item->cid);
       }
diff --git a/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php b/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php
index 91b75ba..2a93827 100644
--- a/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php
+++ b/core/modules/system/src/Tests/Cache/GenericCacheBackendUnitTestBase.php
@@ -531,6 +531,13 @@ function testDeleteTags() {
     $this->assertFalse($this->getCacheBackend($bin)->get('test_cid_invalidate2', TRUE), 'Cache items matching tag were deleted.');
     // Test that the cache entry with without a matching tag still exists.
     $this->assertTrue($this->getCacheBackend($bin)->get('test_cid_invalidate1'), 'Cache items not matching tag were not invalidated.');
+
+    // Test that invalid items are deleted.
+    $backend->set('test_cid_invalidate1', $this->defaultValue, Cache::PERMANENT, array('test_tag:1'));
+    $backend->invalidate('test_cid_invalidate1');
+    $this->assertTrue($backend->get('test_cid_invalidate1', TRUE), 'The invalid cache item exists before deleting.');
+    $backend->deleteTags(array('test_tag:1'));
+    $this->assertFalse($backend->get('test_cid_invalidate1', TRUE), 'The invalid cache item was deleted.');
   }
 
   /**
@@ -580,9 +587,20 @@ function testInvalidate() {
     $ret = $backend->getMultiple($cids, TRUE);
     $this->assertEqual(count($ret), 4, 'Four items returned.');
 
+    // Test that calling invalidate() does not change data.
+    $this->assertIdentical($ret['test1']->data, 1);
+    // Test that calling invalidateMultiple() does not change data.
+    $this->assertIdentical($ret['test2']->data, 2);
+
     // Calling invalidateMultiple() with an empty array should not cause an
     // error.
     $this->assertFalse($backend->invalidateMultiple(array()));
+
+    // Test that an invalidated item is deleted with deleteTags().
+    $backend->set('test5', 5, Cache::PERMANENT, array('test_tag:5'));
+    $backend->invalidate('test5');
+    $backend->deleteTags(array('test_tag:5'));
+    $this->assertFalse($backend->get('test5', TRUE));
   }
 
   /**
@@ -664,6 +682,20 @@ public function testInvalidateAll() {
     $this->assertTrue($unrelated->get('test3'), 'Item in other bin is preserved.');
     $this->assertTrue($backend->get('test1', TRUE), 'First key has not been deleted.');
     $this->assertTrue($backend->get('test2', TRUE), 'Second key has not been deleted.');
+    // Test that calling invalidateAll() does not change data.
+    $this->assertIdentical($backend->get('test1', TRUE)->data, 1);
+
+    // Test that an invalidated item is deleted with deleteTags().
+    $backend->set('test4', 4, Cache::PERMANENT, array('test_tag:4'));
+    $backend->invalidateAll();
+    $backend->deleteTags(array('test_tag:4'));
+    $this->assertFalse($backend->get('test4', TRUE));
+
+    // Test that a deleted item is still deleted after invalidateAll().
+    $backend->set('test5', 5, Cache::PERMANENT, array('test_tag:5'));
+    $backend->deleteTags(array('test_tag:5'));
+    $backend->invalidateAll();
+    $this->assertFalse($backend->get('test5', TRUE));
   }
 
 }
