diff --git a/core/core.services.yml b/core/core.services.yml
index 3e2feb6..a666703 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -32,6 +32,15 @@ services:
     class: Drupal\Core\Cache\TimeZoneCacheContext
     tags:
       - { name: cache.context}
+  cache_tags:
+    class: Drupal\Core\Cache\CacheTagHandler
+    tags:
+      - { name: service_collector }
+  cache_tag_storage:
+    class: Drupal\Core\Cache\DatabaseCacheTagStorage
+    arguments: ['@database']
+    tags:
+      - { name: cache_tags }
   cache.backend.chainedfast:
     class: Drupal\Core\Cache\ChainedFastBackendFactory
     arguments: ['@settings']
@@ -39,12 +48,16 @@ services:
       - [setContainer, ['@service_container']]
   cache.backend.database:
     class: Drupal\Core\Cache\DatabaseBackendFactory
-    arguments: ['@database']
+    arguments: ['@database', '@cache_tag_storage']
   cache.backend.apcu:
     class: Drupal\Core\Cache\ApcuBackendFactory
     arguments: ['@app.root']
+    tags:
+      - { name: cache_tags }
   cache.backend.php:
     class: Drupal\Core\Cache\PhpBackendFactory
+    tags:
+      - { name: cache_tags }
   cache.bootstrap:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
@@ -98,6 +111,7 @@ services:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
       - { name: cache.bin, default_backend: cache.backend.chainedfast }
+      - { name: cache_tags }
     factory_method: get
     factory_service: cache_factory
     arguments: [discovery]
diff --git a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php
index ffe5993..dd77ed1 100644
--- a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php
@@ -9,7 +9,7 @@
 
 use \Drupal\Component\Utility\Crypt;
 
-class ApcuBackendFactory implements CacheFactoryInterface {
+class ApcuBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface {
 
   /**
    * The site prefix string.
@@ -41,4 +41,43 @@ public function get($bin) {
     return new ApcuBackend($bin, $this->sitePrefix);
   }
 
+  /**
+   * Deletes items with any of the specified tags.
+   *
+   * If the cache items are being deleted because they are no longer "fresh",
+   * you may consider using invalidateTags() instead. This allows callers to
+   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
+   * In some cases an invalid item may be acceptable rather than having to
+   * rebuild the cache.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll()
+   */
+  public function deleteTags(array $tags) {
+    // TODO: Implement deleteTags() method.
+  }
+
+  /**
+   * Marks cache items with any of the specified tags as invalid.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
+   */
+  public function invalidateTags(array $tags) {
+    // TODO: Implement invalidateTags() method.
+  }
 }
diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php
index ddf444e..b8e6cdc 100644
--- a/core/lib/Drupal/Core/Cache/Cache.php
+++ b/core/lib/Drupal/Core/Cache/Cache.php
@@ -96,41 +96,25 @@ public static function buildTags($prefix, array $suffixes) {
   /**
    * Deletes items from all bins with any of the specified tags.
    *
-   * Many sites have more than one active cache backend, and each backend may
-   * use a different strategy for storing tags against cache items, and
-   * deleting cache items associated with a given tag.
-   *
-   * When deleting a given list of tags, we iterate over each cache backend, and
-   * and call deleteTags() on each.
-   *
    * @param string[] $tags
    *   The list of tags to delete cache items for.
    */
   public static function deleteTags(array $tags) {
+    // @todo Move to service.
     static::validateTags($tags);
-    foreach (static::getBins() as $cache_backend) {
-      $cache_backend->deleteTags($tags);
-    }
+    \Drupal::service('cache_tags')->deleteTags($tags);
   }
 
   /**
    * Marks cache items from all bins with any of the specified tags as invalid.
    *
-   * Many sites have more than one active cache backend, and each backend my use
-   * a different strategy for storing tags against cache items, and invalidating
-   * cache items associated with a given tag.
-   *
-   * When invalidating a given list of tags, we iterate over each cache backend,
-   * and call invalidateTags() on each.
-   *
    * @param string[] $tags
    *   The list of tags to invalidate cache items for.
    */
   public static function invalidateTags(array $tags) {
+    // @todo Move to service.
     static::validateTags($tags);
-    foreach (static::getBins() as $cache_backend) {
-      $cache_backend->invalidateTags($tags);
-    }
+    \Drupal::service('cache_tags')->invalidateTags($tags);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
index 39c8c26..fd1ae87 100644
--- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
+++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php
@@ -18,7 +18,7 @@
  *
  * @ingroup cache
  */
-interface CacheBackendInterface {
+interface CacheBackendInterface extends CacheTagInvalidationInterface {
 
   /**
    * Indicates that the item should never be removed unless explicitly deleted.
@@ -161,27 +161,6 @@ public function delete($cid);
   public function deleteMultiple(array $cids);
 
   /**
-   * Deletes items with any of the specified tags.
-   *
-   * If the cache items are being deleted because they are no longer "fresh",
-   * you may consider using invalidateTags() instead. This allows callers to
-   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
-   * In some cases an invalid item may be acceptable rather than having to
-   * rebuild the cache.
-   *
-   * @param array $tags
-   *   Associative array of tags, in the same format that is passed to
-   *   CacheBackendInterface::set().
-   *
-   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateTags()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::delete()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll()
-   */
-  public function deleteTags(array $tags);
-
-  /**
    * Deletes all cache items in a bin.
    *
    * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
@@ -224,21 +203,6 @@ public function invalidate($cid);
   public function invalidateMultiple(array $cids);
 
   /**
-   * Marks cache items with any of the specified tags as invalid.
-   *
-   * @param array $tags
-   *   Associative array of tags, in the same format that is passed to
-   *   CacheBackendInterface::set().
-   *
-   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteTags()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple()
-   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
-   */
-  public function invalidateTags(array $tags);
-
-  /**
    * Marks all cache items as invalid.
    *
    * Invalid items may be returned in later calls to get(), if the $allow_invalid
diff --git a/core/lib/Drupal/Core/Cache/CacheTagHandler.php b/core/lib/Drupal/Core/Cache/CacheTagHandler.php
new file mode 100644
index 0000000..d439954
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheTagHandler.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\CacheTagHandler.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Passes cache tag events to classes that wish to respond to them.
+ */
+class CacheTagHandler implements CacheTagHandlerInterface {
+
+  /**
+   * Holds an array of cache tag invalidators.
+   *
+   * @var CacheTagInvalidationInterface[]
+   */
+  protected $invalidators;
+
+  public function invalidateTags(array $tags) {
+    foreach ($this->invalidators as $invalidator) {
+      $invalidator->invalidateTags($tags);
+    }
+  }
+
+  public function deleteTags(array $tags) {
+    foreach ($this->invalidators as $invalidator) {
+      $invalidator->deleteTags($tags);
+    }
+  }
+
+  public function addHandler(CacheTagInvalidationInterface $service) {
+    $this->invalidators[] = $service;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Cache/CacheTagHandlerInterface.php b/core/lib/Drupal/Core/Cache/CacheTagHandlerInterface.php
new file mode 100644
index 0000000..288e04b
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheTagHandlerInterface.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\CacheTagHandlerInterface
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines required methods for classes wanting to handle cache tag changes.
+ */
+interface CacheTagHandlerInterface {
+
+  /**
+   * Marks cache items with any of the specified tags as invalid.
+   *
+   * @param string[] $tags
+   *   The list of tags for which to invalidate cache items.
+   */
+  public function invalidateTags(array $tags);
+
+  /**
+   * Deletes cache items with any of the specified tags.
+   *
+   * @param string[] $tags
+   *   The list of tags for which to delete cache items.
+   */
+  public function deleteTags(array $tags);
+
+}
diff --git a/core/lib/Drupal/Core/Cache/CacheTagInvalidationInterface.php b/core/lib/Drupal/Core/Cache/CacheTagInvalidationInterface.php
new file mode 100644
index 0000000..6efb15a
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheTagInvalidationInterface.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\CacheTagInvalidationInterface.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines methods required for classes that respond to cache tag invalidations.
+ */
+interface CacheTagInvalidationInterface {
+
+  /**
+   * Deletes items with any of the specified tags.
+   *
+   * If the cache items are being deleted because they are no longer "fresh",
+   * you may consider using invalidateTags() instead. This allows callers to
+   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
+   * In some cases an invalid item may be acceptable rather than having to
+   * rebuild the cache.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll()
+   */
+  public function deleteTags(array $tags);
+
+  /**
+   * Marks cache items with any of the specified tags as invalid.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
+   */
+  public function invalidateTags(array $tags);
+
+}
diff --git a/core/lib/Drupal/Core/Cache/CacheTagInvalidationStorageInterface.php b/core/lib/Drupal/Core/Cache/CacheTagInvalidationStorageInterface.php
new file mode 100644
index 0000000..d039f00
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheTagInvalidationStorageInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\CacheTagInvalidationStorageInterface.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * An interface defining cache tag invalidation classes with storage.
+ */
+interface CacheTagInvalidationStorageInterface {
+
+  /**
+   * Returns cache tag invalidations.
+   *
+   * @return array
+   */
+  public function getTagInvalidations();
+
+  /**
+   * Returns cache tag deletions.
+   *
+   * @return array
+   */
+  public function getTagDeletions();
+}
diff --git a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
index c261b84..90eef28 100644
--- a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
@@ -12,7 +12,7 @@
 /**
  * Defines the chained fast cache backend factory.
  */
-class ChainedFastBackendFactory implements CacheFactoryInterface {
+class ChainedFastBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface {
 
   use ContainerAwareTrait;
 
@@ -53,7 +53,7 @@ public function __construct(Settings $settings = NULL, $consistent_service_name
     }
 
     // Default the fast backend to APCu if it's available.
-    if (!isset($fast_service_name) && function_exists('apc_fetch')) {
+    if (FALSE && !isset($fast_service_name) && function_exists('apc_fetch')) {
       $fast_service_name = 'cache.backend.apcu';
     }
 
@@ -85,4 +85,43 @@ public function get($bin) {
     }
   }
 
+  /**
+   * Deletes items with any of the specified tags.
+   *
+   * If the cache items are being deleted because they are no longer "fresh",
+   * you may consider using invalidateTags() instead. This allows callers to
+   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
+   * In some cases an invalid item may be acceptable rather than having to
+   * rebuild the cache.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll()
+   */
+  public function deleteTags(array $tags) {
+    // TODO: Implement deleteTags() method.
+  }
+
+  /**
+   * Marks cache items with any of the specified tags as invalid.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
+   */
+  public function invalidateTags(array $tags) {
+    // TODO: Implement invalidateTags() method.
+  }
 }
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index 813c00a..0ef37d7 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -35,19 +35,29 @@ class DatabaseBackend implements CacheBackendInterface {
   protected $connection;
 
   /**
+   * Storage for cache tag invalidations and deletions.
+   *
+   * @var \Drupal\Core\Cache\CacheTagInvalidationStorageInterface
+   */
+  protected $cacheTagStorage;
+
+  /**
    * Constructs a DatabaseBackend object.
    *
    * @param \Drupal\Core\Database\Connection $connection
    *   The database connection.
+   * @param \Drupal\Core\Cache\CacheTagInvalidationStorageInterface $cacheTagStorage
+   *   The object that stores cache tag invalidations and deletions.
    * @param string $bin
    *   The cache bin for which the object is created.
    */
-  public function __construct(Connection $connection, $bin) {
+  public function __construct(Connection $connection, CacheTagInvalidationStorageInterface $cacheTagStorage, $bin) {
     // All cache tables should be prefixed with 'cache_'.
     $bin = 'cache_' . $bin;
 
     $this->bin = $bin;
     $this->connection = $connection;
+    $this->cacheTagStorage = $cacheTagStorage;
   }
 
   /**
@@ -174,8 +184,8 @@ public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array
    * Actually set the cache.
    */
   protected function doSet($cid, $data, $expire, $tags) {
-    $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array());
-    $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array());
+    $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::deletedTags', array());
+    $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::invalidatedTags', array());
     // Remove tags that were already deleted or invalidated during this request
     // from the static caches so that another deletion or invalidation can
     // occur.
@@ -215,8 +225,8 @@ protected function doSet($cid, $data, $expire, $tags) {
    * {@inheritdoc}
    */
   public function setMultiple(array $items) {
-    $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array());
-    $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array());
+    $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::deletedTags', array());
+    $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::invalidatedTags', array());
 
     // Use a transaction so that the database can write the changes in a single
     // commit.
@@ -319,28 +329,7 @@ public function deleteMultiple(array $cids) {
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags().
    */
-  public function deleteTags(array $tags) {
-    $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array());
-    $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::deletedTags', array());
-    foreach ($tags as $tag) {
-      // Only delete tags once per request unless they are written again.
-      if (isset($deleted_tags[$tag])) {
-        continue;
-      }
-      $deleted_tags[$tag] = TRUE;
-      unset($tag_cache[$tag]);
-      try {
-        $this->connection->merge('cachetags')
-          ->insertFields(array('deletions' => 1))
-          ->expression('deletions', 'deletions + 1')
-          ->key('tag', $tag)
-          ->execute();
-      }
-      catch (\Exception $e) {
-        $this->catchException($e, 'cachetags');
-      }
-    }
-  }
+  public function deleteTags(array $tags) {}
 
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll().
@@ -386,30 +375,9 @@ public function invalidateMultiple(array $cids) {
   }
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
+   * Implements Drupal\Core\Cache\CacheTagHandlerInterface::invalidateTags().
    */
-  public function invalidateTags(array $tags) {
-    try {
-      $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array());
-      $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseBackend::invalidatedTags', array());
-      foreach ($tags as $tag) {
-        // Only invalidate tags once per request unless they are written again.
-        if (isset($invalidated_tags[$tag])) {
-          continue;
-        }
-        $invalidated_tags[$tag] = TRUE;
-        unset($tag_cache[$tag]);
-        $this->connection->merge('cachetags')
-          ->insertFields(array('invalidations' => 1))
-          ->expression('invalidations', 'invalidations + 1')
-          ->key('tag', $tag)
-          ->execute();
-      }
-    }
-    catch (\Exception $e) {
-      $this->catchException($e, 'cachetags');
-    }
-  }
+  public function invalidateTags(array $tags) {}
 
   /**
    * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateAll().
@@ -452,7 +420,7 @@ public function garbageCollection() {
    *   Sum of all invalidations.
    */
   protected function checksumTags(array $tags) {
-    $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache', array());
+    $tag_cache = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache', array());
 
     $checksum = array(
       'invalidations' => 0,
@@ -516,14 +484,16 @@ protected function ensureBinExists() {
   /**
    * Act on an exception when cache might be stale.
    *
-   * If the {cachetags} table does not yet exist, that's fine but if the table
+   * If the table does not yet exist, that's fine, but if the table
    * exists and yet the query failed, then the cache is stale and the
    * exception needs to propagate.
    *
    * @param $e
    *   The exception.
    * @param string|null $table_name
-   *   The table name, defaults to $this->bin. Can be cachetags.
+   *   The table name. Defaults to $this->bin.
+   *
+   * @throws \Exception
    */
   protected function catchException(\Exception $e, $table_name = NULL) {
     if ($this->connection->schema()->tableExists($table_name ?: $this->bin)) {
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php
index 1d70164..2772bab 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php
@@ -23,8 +23,9 @@ class DatabaseBackendFactory implements CacheFactoryInterface {
    *
    * @param \Drupal\Core\Database\Connection $connection
    */
-  function __construct(Connection $connection) {
+  function __construct(Connection $connection, CacheTagInvalidationStorageInterface $cacheTagStorage) {
     $this->connection = $connection;
+    $this->cacheTagStorage = $cacheTagStorage;
   }
 
   /**
@@ -37,7 +38,7 @@ function __construct(Connection $connection) {
    *   The cache backend object for the specified cache bin.
    */
   function get($bin) {
-    return new DatabaseBackend($this->connection, $bin);
+    return new DatabaseBackend($this->connection, $this->cacheTagStorage, $bin);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Cache/DatabaseCacheTagStorage.php b/core/lib/Drupal/Core/Cache/DatabaseCacheTagStorage.php
new file mode 100644
index 0000000..0a9259c
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/DatabaseCacheTagStorage.php
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\DatabaseCacheTagStorage.
+ */
+
+namespace Drupal\Core\Cache;
+
+use \Drupal\Core\Database\Connection;
+
+/**
+ * Storage for cache tag invalidations and deletions.
+ */
+class DatabaseCacheTagStorage implements CacheTagInvalidationStorageInterface, CacheTagInvalidationInterface {
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * Constructs a DatabaseBackend object.
+   *
+   * @param \Drupal\Core\Database\Connection $connection
+   *   The database connection.
+   */
+  public function __construct(Connection $connection) {
+    $this->connection = $connection;
+  }
+
+  /**
+   * Stores cache tag invalidations.
+   *
+   * @param string[] $tags
+   *   The list of tags for which to store invalidations.
+   */
+  public function invalidateTags(array $tags) {
+    try {
+      $tag_cache = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache', array());
+      $invalidated_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::invalidatedTags', array());
+      foreach ($tags as $tag) {
+        // Only invalidate tags once per request unless they are written again.
+        if (isset($invalidated_tags[$tag])) {
+          continue;
+        }
+        $invalidated_tags[$tag] = TRUE;
+        unset($tag_cache[$tag]);
+        $this->connection->merge('cachetags')
+          ->insertFields(array('invalidations' => 1))
+          ->expression('invalidations', 'invalidations + 1')
+          ->key('tag', $tag)
+          ->execute();
+      }
+    }
+    catch (\Exception $e) {
+      $this->catchException($e, 'cachetags');
+    }
+  }
+
+  /**
+   * Stores cache tag deletions.
+   *
+   * @param string[] $tags
+   *   The list of tags for which to store deletions.
+   */
+  public function deleteTags(array $tags) {
+    $tag_cache = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::tagCache', array());
+    $deleted_tags = &drupal_static('Drupal\Core\Cache\DatabaseCacheTagStorage::deletedTags', array());
+    foreach ($tags as $tag) {
+      // Only delete tags once per request unless they are written again.
+      if (isset($deleted_tags[$tag])) {
+        continue;
+      }
+      $deleted_tags[$tag] = TRUE;
+      unset($tag_cache[$tag]);
+      try {
+        $this->connection->merge('cachetags')
+          ->insertFields(array('deletions' => 1))
+          ->expression('deletions', 'deletions + 1')
+          ->key('tag', $tag)
+          ->execute();
+      }
+      catch (\Exception $e) {
+        $this->catchException($e);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTagInvalidations() {
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTagDeletions() {
+
+  }
+
+  /**
+   * Act on an exception when cache might be stale.
+   *
+   * If the {cachetags} table does not yet exist, that's fine but if the table
+   * exists and yet the query failed, then the cache is stale and the
+   * exception needs to propagate.
+   *
+   * @param \Exception $e
+   *   The exception.
+   *
+   * @throws \Exception
+   */
+  protected function catchException(\Exception $e) {
+    if ($this->connection->schema()->tableExists('cachetags')) {
+      throw $e;
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php
index c9e288d..7317d39 100644
--- a/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Cache;
 
-class MemoryBackendFactory implements CacheFactoryInterface {
+class MemoryBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface {
 
   /**
    * {@inheritdoc}
@@ -16,4 +16,43 @@ function get($bin) {
     return new MemoryBackend($bin);
   }
 
+  /**
+   * Deletes items with any of the specified tags.
+   *
+   * If the cache items are being deleted because they are no longer "fresh",
+   * you may consider using invalidateTags() instead. This allows callers to
+   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
+   * In some cases an invalid item may be acceptable rather than having to
+   * rebuild the cache.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll()
+   */
+  public function deleteTags(array $tags) {
+    // TODO: Implement deleteTags() method.
+  }
+
+  /**
+   * Marks cache items with any of the specified tags as invalid.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
+   */
+  public function invalidateTags(array $tags) {
+    // TODO: Implement invalidateTags() method.
+  }
 }
diff --git a/core/lib/Drupal/Core/Cache/NullBackend.php b/core/lib/Drupal/Core/Cache/NullBackend.php
index d27bc13..fb898de 100644
--- a/core/lib/Drupal/Core/Cache/NullBackend.php
+++ b/core/lib/Drupal/Core/Cache/NullBackend.php
@@ -70,7 +70,7 @@ public function deleteMultiple(array $cids) {}
   public function deleteAll() {}
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteTags().
+   * Implements Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags().
    */
   public function deleteTags(array $tags) {}
 
@@ -85,7 +85,7 @@ public function invalidate($cid) {}
   public function invalidateMultiple(array $cids) {}
 
   /**
-   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
+   * Implements Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags().
    */
   public function invalidateTags(array $tags) {}
 
diff --git a/core/lib/Drupal/Core/Cache/NullBackendFactory.php b/core/lib/Drupal/Core/Cache/NullBackendFactory.php
index 0101a8e..b1d9365 100644
--- a/core/lib/Drupal/Core/Cache/NullBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/NullBackendFactory.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Cache;
 
-class NullBackendFactory implements CacheFactoryInterface {
+class NullBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface {
 
   /**
    * {@inheritdoc}
@@ -16,4 +16,43 @@ function get($bin) {
     return new NullBackend($bin);
   }
 
+  /**
+   * Deletes items with any of the specified tags.
+   *
+   * If the cache items are being deleted because they are no longer "fresh",
+   * you may consider using invalidateTags() instead. This allows callers to
+   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
+   * In some cases an invalid item may be acceptable rather than having to
+   * rebuild the cache.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll()
+   */
+  public function deleteTags(array $tags) {
+    // TODO: Implement deleteTags() method.
+  }
+
+  /**
+   * Marks cache items with any of the specified tags as invalid.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
+   */
+  public function invalidateTags(array $tags) {
+    // TODO: Implement invalidateTags() method.
+  }
 }
diff --git a/core/lib/Drupal/Core/Cache/NullCacheTagHandler.php b/core/lib/Drupal/Core/Cache/NullCacheTagHandler.php
new file mode 100644
index 0000000..76b4c41
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/NullCacheTagHandler.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\NullCacheTagHandler.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * A no-op implementation of CacheTagHandlerInterface, for the installer.
+ */
+class NullCacheTagHandler implements CacheTagHandlerInterface {
+
+  /**
+   * Holds an array of cache tag invalidators.
+   *
+   * @var CacheTagInvalidationInterface[]
+   */
+  protected $invalidators;
+
+  public function invalidateTags(array $tags) {}
+
+  public function deleteTags(array $tags) {}
+
+  public function addHandler(CacheTagInvalidationInterface $service) {
+    $this->invalidators[] = $service;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Cache/PhpBackendFactory.php b/core/lib/Drupal/Core/Cache/PhpBackendFactory.php
index 0801b72..872bf16 100644
--- a/core/lib/Drupal/Core/Cache/PhpBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/PhpBackendFactory.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Cache;
 
-class PhpBackendFactory implements CacheFactoryInterface {
+class PhpBackendFactory implements CacheFactoryInterface, CacheTagInvalidationInterface {
 
   /**
    * Gets PhpBackend for the specified cache bin.
@@ -22,4 +22,43 @@ function get($bin) {
     return new PhpBackend($bin);
   }
 
+  /**
+   * Deletes items with any of the specified tags.
+   *
+   * If the cache items are being deleted because they are no longer "fresh",
+   * you may consider using invalidateTags() instead. This allows callers to
+   * retrieve the invalid items by calling get() with $allow_invalid set to TRUE.
+   * In some cases an invalid item may be acceptable rather than having to
+   * rebuild the cache.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::invalidateTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::delete()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::deleteAll()
+   */
+  public function deleteTags(array $tags) {
+    // TODO: Implement deleteTags() method.
+  }
+
+  /**
+   * Marks cache items with any of the specified tags as invalid.
+   *
+   * @param array $tags
+   *   Associative array of tags, in the same format that is passed to
+   *   CacheBackendInterface::set().
+   *
+   * @see \Drupal\Core\Cache\CacheBackendInterface::set()
+   * @see \Drupal\Core\Cache\CacheTagInvalidationInterface::deleteTags()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidate()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateMultiple()
+   * @see \Drupal\Core\Cache\CacheBackendInterface::invalidateAll()
+   */
+  public function invalidateTags(array $tags) {
+    // TODO: Implement invalidateTags() method.
+  }
 }
diff --git a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php
index 6e93561..af823f7 100644
--- a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php
+++ b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php
@@ -48,6 +48,8 @@ public function register(ContainerBuilder $container) {
       ->addArgument(new Reference('request_stack'));
     $container
       ->register('router.dumper', 'Drupal\Core\Routing\NullMatcherDumper');
+    $container
+      ->register('cache_tags', 'Drupal\Core\Cache\NullCacheTagHandler');
 
     // Replace the route builder with an empty implementation.
     // @todo Convert installer steps into routes; add an installer.routing.yml.
diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php
index cf5b3f1..d8744d8 100644
--- a/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php
+++ b/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php
@@ -48,7 +48,7 @@ class CacheCollectorTest extends UnitTestCase {
    * {@inheritdoc}
    */
   protected function setUp() {
-    $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $this->cache = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface');
     $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface');
     $this->cid = $this->randomMachineName();
     $this->collector = new CacheCollectorHelper($this->cid, $this->cache, $this->lock);
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
index 2da84fe..02ce8b5 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
@@ -79,9 +79,9 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
   /**
    * The mocked cache backend.
    *
-   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
+   * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
    */
-  protected $cacheBackend;
+  protected $cacheTagHandler;
 
   /**
    * The mocked typed config manager.
@@ -121,7 +121,7 @@ protected function setUp() {
       ->with('en')
       ->will($this->returnValue(new Language(array('id' => 'en'))));
 
-    $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface');
 
     $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
 
@@ -129,9 +129,8 @@ protected function setUp() {
     $container->set('entity.manager', $this->entityManager);
     $container->set('uuid', $this->uuid);
     $container->set('language_manager', $this->languageManager);
-    $container->set('cache.test', $this->cacheBackend);
+    $container->set('cache_tags', $this->cacheTagHandler);
     $container->set('config.typed', $this->typedConfigManager);
-    $container->setParameter('cache_bins', array('cache.test' => 'test'));
     \Drupal::setContainer($container);
 
     $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', array($values, $this->entityTypeId));
@@ -361,7 +360,7 @@ public function testEnable() {
    * @depends testSetStatus
    */
   public function testDisable() {
-    $this->cacheBackend->expects($this->once())
+    $this->cacheTagHandler->expects($this->once())
       ->method('invalidateTags')
       ->with(array($this->entityTypeId . ':' . $this->id));
 
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
index ddfbd81..bf7ca84 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
@@ -85,9 +85,9 @@ class ConfigEntityStorageTest extends UnitTestCase {
   /**
    * The mocked cache backend.
    *
-   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
+   * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
    */
-  protected $cacheBackend;
+  protected $cacheTagHandler;
 
   /**
    * The mocked typed config manager.
@@ -153,7 +153,7 @@ protected function setUp() {
       ->with('test_entity_type')
       ->will($this->returnValue($this->entityType));
 
-    $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface');
 
     $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
     $this->typedConfigManager->expects($this->any())
@@ -162,8 +162,7 @@ protected function setUp() {
     $container = new ContainerBuilder();
     $container->set('entity.manager', $this->entityManager);
     $container->set('config.typed', $this->typedConfigManager);
-    $container->set('cache.test', $this->cacheBackend);
-    $container->setParameter('cache_bins', array('cache.test' => 'test'));
+    $container->set('cache_tags', $this->cacheTagHandler);
     \Drupal::setContainer($container);
 
   }
@@ -173,7 +172,7 @@ protected function setUp() {
    * @covers ::doCreate
    */
   public function testCreateWithPredefinedUuid() {
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $this->moduleHandler->expects($this->at(0))
@@ -198,7 +197,7 @@ public function testCreateWithPredefinedUuid() {
    * @return \Drupal\Core\Entity\EntityInterface
    */
   public function testCreate() {
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $this->moduleHandler->expects($this->at(0))
@@ -240,7 +239,7 @@ public function testSaveInsert(EntityInterface $entity) {
     $config_object->expects($this->once())
       ->method('save');
 
-    $this->cacheBackend->expects($this->once())
+    $this->cacheTagHandler->expects($this->once())
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId . '_list', // List cache tag.
@@ -299,7 +298,7 @@ public function testSaveUpdate(EntityInterface $entity) {
     $config_object->expects($this->once())
       ->method('save');
 
-    $this->cacheBackend->expects($this->once())
+    $this->cacheTagHandler->expects($this->once())
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId . ':foo', // Own cache tag.
@@ -359,7 +358,7 @@ public function testSaveRename(ConfigEntityInterface $entity) {
     $config_object->expects($this->once())
       ->method('save');
 
-    $this->cacheBackend->expects($this->once())
+    $this->cacheTagHandler->expects($this->once())
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId .':bar', // Own cache tag.
@@ -403,7 +402,7 @@ public function testSaveRename(ConfigEntityInterface $entity) {
    * @expectedExceptionMessage The entity does not have an ID.
    */
   public function testSaveInvalid() {
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $entity = $this->getMockEntity();
@@ -428,7 +427,7 @@ public function testSaveDuplicate() {
     $config_object->expects($this->never())
       ->method('save');
 
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $this->configFactory->expects($this->once())
@@ -459,7 +458,7 @@ public function testSaveMismatch() {
     $config_object->expects($this->never())
       ->method('save');
 
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $this->configFactory->expects($this->once())
@@ -492,7 +491,7 @@ public function testSaveNoMismatch() {
     $config_object->expects($this->once())
       ->method('save');
 
-    $this->cacheBackend->expects($this->once())
+    $this->cacheTagHandler->expects($this->once())
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId . '_list', // List cache tag.
@@ -542,7 +541,7 @@ public function testSaveChangedUuid() {
         array('id', 'foo'),
       )));
 
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $this->configFactory->expects($this->at(1))
@@ -699,7 +698,7 @@ public function testLoadRevision() {
    * @covers ::deleteRevision
    */
   public function testDeleteRevision() {
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $this->assertSame(NULL, $this->entityStorage->deleteRevision(1));
@@ -725,7 +724,7 @@ public function testDelete() {
       $config_map[] = array("the_config_prefix.$id", $config_object);
     }
 
-    $this->cacheBackend->expects($this->once())
+    $this->cacheTagHandler->expects($this->once())
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId . ':bar', // Own cache tag.
@@ -775,7 +774,7 @@ public function testDeleteNothing() {
     $this->configFactory->expects($this->never())
       ->method('get');
 
-    $this->cacheBackend->expects($this->never())
+    $this->cacheTagHandler->expects($this->never())
       ->method('invalidateTags');
 
     $this->entityStorage->delete(array());
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
index 933b7ed..beaa312 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
@@ -120,6 +120,7 @@ protected function setUp() {
       ->will($this->returnValue(array()));
 
     $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $cache_tag_handler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface');
 
     $language = $this->getMock('Drupal\Core\Language\LanguageInterface');
     $language->expects($this->any())
@@ -139,7 +140,7 @@ protected function setUp() {
     $this->formBuilder = $this->getMock('Drupal\Core\Form\FormBuilderInterface');
     $this->controllerResolver = $this->getClassResolverStub();
 
-    $this->container = $this->getContainerWithCacheBins($this->cache);
+    $this->container = $this->getContainerWithCacheBins($cache_tag_handler);
 
     $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
 
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php
index 6535732..c512fb1 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php
@@ -75,9 +75,9 @@ class EntityUnitTest extends UnitTestCase {
   /**
    * The mocked cache backend.
    *
-   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
+   * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
    */
-  protected $cacheBackend;
+  protected $cacheTagHandler;
 
   /**
    * The entity values.
@@ -116,14 +116,13 @@ protected function setUp() {
       ->with('en')
       ->will($this->returnValue(new Language(array('id' => 'en'))));
 
-    $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandler');
 
     $container = new ContainerBuilder();
     $container->set('entity.manager', $this->entityManager);
     $container->set('uuid', $this->uuid);
     $container->set('language_manager', $this->languageManager);
-    $container->set('cache.test', $this->cacheBackend);
-    $container->setParameter('cache_bins', array('cache.test' => 'test'));
+    $container->set('cache_tags', $this->cacheTagHandler);
     \Drupal::setContainer($container);
 
     $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Entity\Entity', array($this->values, $this->entityTypeId));
@@ -393,12 +392,12 @@ public function testPreSave() {
    * @covers ::postSave
    */
   public function testPostSave() {
-    $this->cacheBackend->expects($this->at(0))
+    $this->cacheTagHandler->expects($this->at(0))
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId . '_list', // List cache tag.
       ));
-    $this->cacheBackend->expects($this->at(1))
+    $this->cacheTagHandler->expects($this->at(1))
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId . ':' . $this->values['id'], // Own cache tag.
@@ -450,7 +449,7 @@ public function testPreDelete() {
    * @covers ::postDelete
    */
   public function testPostDelete() {
-    $this->cacheBackend->expects($this->once())
+    $this->cacheTagHandler->expects($this->once())
       ->method('invalidateTags')
       ->with(array(
         $this->entityTypeId . ':' . $this->values['id'],
diff --git a/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php
index ee10e54..a79b9c3 100644
--- a/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php
@@ -70,9 +70,9 @@ class KeyValueEntityStorageTest extends UnitTestCase {
   /**
    * The mocked cache backend.
    *
-   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
+   * @var \Drupal\Core\Cache\cacheTagHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
    */
-  protected $cacheBackend;
+  protected $cacheTagHandler;
 
   /**
    * {@inheritdoc}
@@ -110,7 +110,7 @@ protected function setUpKeyValueEntityStorage($uuid_key = 'uuid') {
       ->with('test_entity_type')
       ->will($this->returnValue($this->entityType));
 
-    $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $this->cacheTagHandler = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface');
 
     $this->keyValueStore = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface');
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
@@ -130,8 +130,7 @@ protected function setUpKeyValueEntityStorage($uuid_key = 'uuid') {
     $container = new ContainerBuilder();
     $container->set('entity.manager', $this->entityManager);
     $container->set('language_manager', $this->languageManager);
-    $container->set('cache.test', $this->cacheBackend);
-    $container->setParameter('cache_bins', array('cache.test' => 'test'));
+    $container->set('cache_tags', $this->cacheTagHandler);
     \Drupal::setContainer($container);
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
index 0a58e81..89ed10c 100644
--- a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
+++ b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
@@ -121,7 +121,7 @@ protected function setUp() {
     $logger = $this->getMock('Psr\Log\LoggerInterface');
     $this->themeHandler = new TestThemeHandler($this->root, $this->configFactory, $this->moduleHandler, $this->state, $this->infoParser, $logger, $this->cssCollectionOptimizer, $this->configInstaller, $this->configManager, $this->routeBuilderIndicator, $this->extensionDiscovery);
 
-    $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $cache_backend = $this->getMock('Drupal\Core\Cache\CacheTagHandlerInterface');
     $this->getContainerWithCacheBins($cache_backend);
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
index c2ef841..e9bd4ce 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
@@ -190,7 +190,7 @@ public function testDefaultPluginManagerWithFilledCache() {
    */
   public function testCacheClearWithTags() {
     $cid = $this->randomMachineName();
-    $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\MemoryBackend')
+    $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\CacheTagHandlerInterface')
       ->disableOriginalConstructor()
       ->getMock();
     $cache_backend
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index 43748e8..268dadd 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -8,8 +8,7 @@
 namespace Drupal\Tests;
 
 use Drupal\Component\Utility\Random;
-use Drupal\Component\Utility\String;
-use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Cache\CacheTagHandlerInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 
 /**
@@ -199,22 +198,18 @@ public function getStringTranslationStub() {
   /**
    * Sets up a container with cache bins.
    *
-   * @param \Drupal\Core\Cache\CacheBackendInterface $backend
+   * @param \Drupal\Core\Cache\CacheTagHandlerInterface $cache_tags_handler
    *   The cache backend to set up.
    *
    * @return \Symfony\Component\DependencyInjection\ContainerInterface|\PHPUnit_Framework_MockObject_MockObject
    *   The container with the cache bins set up.
    */
-  protected function getContainerWithCacheBins(CacheBackendInterface $backend) {
+  protected function getContainerWithCacheBins(CacheTagHandlerInterface $cache_tags_handler) {
     $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
     $container->expects($this->any())
-      ->method('getParameter')
-      ->with('cache_bins')
-      ->will($this->returnValue(array('cache.test' => 'test')));
-    $container->expects($this->any())
       ->method('get')
-      ->with('cache.test')
-      ->will($this->returnValue($backend));
+      ->with('cache_tags')
+      ->will($this->returnValue($cache_tags_handler));
 
     \Drupal::setContainer($container);
     return $container;
diff --git a/sites/development.services.yml b/sites/development.services.yml
index cc21211..75c5f44 100644
--- a/sites/development.services.yml
+++ b/sites/development.services.yml
@@ -5,5 +5,9 @@
 services:
   cache.backend.memory:
     class: Drupal\Core\Cache\MemoryBackendFactory
+    tags:
+      - { name: cache_tags }
   cache.backend.null:
     class: Drupal\Core\Cache\NullBackendFactory
+    tags:
+      - { name: cache_tags }
