diff --git a/core/lib/Drupal/Core/Cache/ArrayBackend.php b/core/lib/Drupal/Core/Cache/ArrayBackend.php
new file mode 100644
index 0000000..e0978fc
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/ArrayBackend.php
@@ -0,0 +1,213 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Cache\ArrayBackend.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Defines a memory cache implementation.
+ *
+ * Stores cache items in a PHP array.
+ *
+ * Should be used for unit tests and specialist use-cases only, does not
+ * store cached items between requests. 
+ *
+ */
+class DatabaseBackend implements CacheBackendInterface {
+
+  /**
+   * @var array 
+   */
+  protected $cache;
+
+  /**
+   * All tags checked during the request.
+   */
+  protected $tags = array();
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::get().
+   */
+  function get($cid) {
+    $cids = array($cid);
+    $cache = $this->getMultiple($cids);
+    return reset($cache);
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::getMultiple().
+   */
+  function getMultiple(&$cids) {
+    $return = array();
+    $items = array_intersect_key($this->cache, array_flip($cids));
+    foreach ($items as $item) {
+      $item = $this->prepareItem($item);
+      if ($item) {
+        $return[$item->cid] = $item;
+      }
+    }
+    $cids = array_diff($cids, array_keys($cache));
+  }
+
+  /**
+   * Prepares a cached item.
+   *
+   * Checks that items are either permanent or did not expire, and unserializes
+   * data as appropriate.
+   *
+   * @param stdClass $cache
+   *   An item loaded from cache_get() or cache_get_multiple().
+   *
+   * @return mixed
+   *   The item with data unserialized as appropriate or FALSE if there is no
+   *   valid item to load.
+   */
+  protected function prepareItem($cache) {
+    if (!isset($cache->data)) {
+      return FALSE;
+    }
+
+    // The cache data is invalid if any of its tags have been cleared since.
+    if ($cache->tags) {
+      $cache->tags = explode(' ', $cache->tags);
+      if (!$this->validTags($cache->checksum, $cache->tags)) {
+        return FALSE;
+      }
+    }
+
+    return $cache;
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::set().
+   */
+  function set($cid, $data, $expire = CACHE_PERMANENT, array $tags = array()) {
+    $this->cache[$cid] = (object) func_get_args();
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::delete().
+   */
+  function delete($cid) {
+    unset($this->cache[$cid]);
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deleteMultiple().
+   */
+  function deleteMultiple(array $cids) {
+    $this->cache = array_diff($this->cache, array_flip($cids));
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::deletePrefix().
+   */
+  function deletePrefix($prefix) {
+    foreach ($this->cache as $cid => $item) {
+      if (strpos($cid, $prefix) === 0) {
+        unset($this->cache[$cid]);
+      }
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::flush().
+   */
+  function flush() {
+    $this->cache = array();
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::expire().
+   */
+  function expire() {
+    // @todo: minimum cache lifetime is on its way out.
+  }
+
+  /**
+   * Compares two checksums of tags. Used to determine whether to serve a cached
+   * item or treat it as invalidated.
+   *
+   * @param integer @checksum
+   *   The initial checksum to compare against.
+   * @param array @tags
+   *   An array of tags to calculate a checksum for.
+   *
+   * @return boolean
+   *   TRUE if the checksums match, FALSE otherwise.
+   */
+  protected function validTags($checksum, array $tags) {
+    return $checksum == $this->checksumTags($tags);
+  }
+
+  /**
+   * Flattens a tags array into a numeric array suitable for string storage.
+   *
+   * @param array $tags
+   *   Associative array of tags to flatten.
+   *
+   * @return
+   *   Numeric array of flattened tag identifiers.
+   */
+  protected function flattenTags(array $tags) {
+    if (isset($tags[0])) {
+      return $tags;
+    }
+
+    $flat_tags = array();
+    foreach ($tags as $namespace => $values) {
+      if (is_array($values)) {
+        foreach ($values as $value) {
+          $flat_tags[] = "$namespace:$value";
+        }
+      }
+      else {
+        $flat_tags[] = "$namespace:$values";
+      }
+    }
+    return $flat_tags;
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags().
+   */
+  public function invalidateTags(array $tags) {
+    foreach ($this->flattenTags($tags) as $tag) {
+      foreach ($this->tags as $key => $value) {
+        if ($key == $tag) {
+          $this->tags[$key]++;
+        }
+      }
+    }
+  }
+
+  /**
+   * Returns the sum total of validations for a given set of tags.
+   *
+   * @param array $tags
+   *   Associative array of tags.
+   *
+   * @return integer
+   *   Sum of all invalidations.
+   */
+  protected function checksumTags($tags) {
+    $checksum = 0;
+
+   foreach ($this->flattenTags($tags) as $tag) {
+     if (isset($this->tags[$tag])) {
+       $checksum += $this->tags[$tag];
+     }
+   }
+   return $checksum;
+  }
+
+  /**
+   * Implements Drupal\Core\Cache\CacheBackendInterface::isEmpty().
+   */
+  function isEmpty() {
+    return empty($this->cache);
+  }
+}
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 58ea4a6..46e7ad7 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -116,7 +116,7 @@ function comment_entity_info() {
           'custom settings' => FALSE,
         ),
       ),
-      'static cache' => FALSE,
+      'cache controller' => 'Drupal\Core\Cache\NullBackend',
     ),
   );
 
diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module
index c167bd4..16b4b8c 100644
--- a/core/modules/entity/entity.module
+++ b/core/modules/entity/entity.module
@@ -69,7 +69,7 @@ function entity_get_info($entity_type = NULL) {
         $entity_info[$name] += array(
           'fieldable' => FALSE,
           'controller class' => 'Drupal\entity\EntityController',
-          'static cache' => TRUE,
+          'cache controller' => 'Drupal\Core\Cache\MemoryBackend',
           'field cache' => TRUE,
           'load hook' => $name . '_load',
           'bundles' => array(),
diff --git a/core/modules/entity/lib/Drupal/entity/EntityController.php b/core/modules/entity/lib/Drupal/entity/EntityController.php
index 3edc4cc..1c95404 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityController.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityController.php
@@ -20,7 +20,7 @@ use PDO;
 class EntityController implements EntityControllerInterface {
 
   /**
-   * Static cache of entities.
+   * Entity cache controller.
    *
    * @var array
    */
@@ -75,15 +75,6 @@ class EntityController implements EntityControllerInterface {
   protected $revisionTable;
 
   /**
-   * Whether this entity type should use the static cache.
-   *
-   * Set by entity info.
-   *
-   * @var boolean
-   */
-  protected $cache;
-
-  /**
    * Implements Drupal\entity\EntityController::__construct().
    *
    * Sets basic variables.
@@ -91,7 +82,7 @@ class EntityController implements EntityControllerInterface {
   public function __construct($entityType) {
     $this->entityType = $entityType;
     $this->entityInfo = entity_get_info($entityType);
-    $this->entityCache = array();
+    $this->resetCache();
     $this->hookLoadArguments = array();
     $this->idKey = $this->entityInfo['entity keys']['id'];
 
@@ -103,9 +94,6 @@ class EntityController implements EntityControllerInterface {
     else {
       $this->revisionKey = FALSE;
     }
-
-    // Check if the entity type supports static caching of loaded entities.
-    $this->cache = !empty($this->entityInfo['static cache']);
   }
 
   /**
@@ -113,12 +101,11 @@ class EntityController implements EntityControllerInterface {
    */
   public function resetCache(array $ids = NULL) {
     if (isset($ids)) {
-      foreach ($ids as $id) {
-        unset($this->entityCache[$id]);
-      }
+      $this->entityCache->deleteMultiple($ids);
     }
     else {
-      $this->entityCache = array();
+      $class = $this->entityInfo['cache controller'];
+      $this->entityCache = new $class('entity');
     }
   }
 
@@ -144,14 +131,8 @@ class EntityController implements EntityControllerInterface {
     // and we need to know if it's empty for this reason to avoid querying the
     // database when all requested entities are loaded from cache.
     $passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
-    // Try to load entities from the static cache, if the entity type supports
-    // static caching.
-    if ($this->cache && !$revision_id) {
-      $entities += $this->cacheGet($ids, $conditions);
-      // If any entities were loaded, remove them from the ids still to load.
-      if ($passed_ids) {
-        $ids = array_keys(array_diff_key($passed_ids, $entities));
-      }
+    if (!$revision_id) {
+      $entities += $this->entityCache->getMultiple($ids);
     }
 
     // Load any remaining entities from the database. This is the case if $ids
@@ -178,11 +159,9 @@ class EntityController implements EntityControllerInterface {
       $entities += $queried_entities;
     }
 
-    if ($this->cache) {
-      // Add entities to the cache if we are not loading a revision.
-      if (!empty($queried_entities) && !$revision_id) {
-        $this->cacheSet($queried_entities);
-      }
+    // Add entities to the cache if we are not loading a revision.
+    if (!empty($queried_entities) && !$revision_id) {
+      $this->entityCache->set($queried_entities);
     }
 
     // Ensure that the returned array is ordered the same as the original
@@ -308,52 +287,4 @@ class EntityController implements EntityControllerInterface {
       call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args);
     }
   }
-
-  /**
-   * Gets entities from the static cache.
-   *
-   * @param $ids
-   *   If not empty, return entities that match these IDs.
-   * @param $conditions
-   *   If set, return entities that match all of these conditions.
-   *
-   * @return
-   *   Array of entities from the entity cache.
-   */
-  protected function cacheGet($ids, $conditions = array()) {
-    $entities = array();
-    // Load any available entities from the internal cache.
-    if (!empty($this->entityCache)) {
-      if ($ids) {
-        $entities += array_intersect_key($this->entityCache, array_flip($ids));
-      }
-      // If loading entities only by conditions, fetch all available entities
-      // from the cache. Entities which don't match are removed later.
-      elseif ($conditions) {
-        $entities = $this->entityCache;
-      }
-    }
-
-    // Exclude any entities loaded from cache if they don't match $conditions.
-    // This ensures the same behavior whether loading from memory or database.
-    if ($conditions) {
-      foreach ($entities as $entity) {
-        $entity_values = (array) $entity;
-        if (array_diff_assoc($conditions, $entity_values)) {
-          unset($entities[$entity->{$this->idKey}]);
-        }
-      }
-    }
-    return $entities;
-  }
-
-  /**
-   * Stores entities in the static entity cache.
-   *
-   * @param $entities
-   *   Entities to store in the cache.
-   */
-  protected function cacheSet($entities) {
-    $this->entityCache += $entities;
-  }
 }
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index ebc5dcf..d793bc0 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -273,7 +273,7 @@ function system_entity_info() {
         'id' => 'fid',
         'label' => 'filename',
       ),
-      'static cache' => FALSE,
+      'static cache' => 'Drupal\Core\Cach\NullBackend',
     ),
   );
 }
