diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
index 3404957..602ac23 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -131,20 +131,6 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function loadRevision($revision_id) {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteRevision($revision_id) {
-    return NULL;
-  }
-
-  /**
    * Returns the prefix used to create the configuration name.
    *
    * The prefix consists of the config prefix from the entity type plus a dot
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 1e198fe..7855924 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -124,6 +124,13 @@
   protected $translationInitialize = FALSE;
 
   /**
+   * The original revision identifier.
+   *
+   * @var int
+   */
+  protected $originalRevisionId;
+
+  /**
    * Boolean indicating whether a new revision should be created on save.
    *
    * @var bool
@@ -233,6 +240,10 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans
         }
       }
     }
+
+    // Store the original revision identfier the entity has been loaded with to
+    // keep it safe from changes.
+    $this->originalRevisionId = $this->getRevisionId();
   }
 
   /**
@@ -338,6 +349,20 @@ public function getRevisionId() {
   /**
    * {@inheritdoc}
    */
+  public function getOriginalRevisionId() {
+    return $this->originalRevisionId;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function resetOriginalRevisionId() {
+    $this->originalRevisionId = $this->getRevisionId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isTranslatable() {
     // Check that the bundle is translatable, the entity has a language defined
     // and if we have more than one language on the site.
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index 5eb5c30..f5be3c0 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -26,6 +26,13 @@
   protected $bundleKey = FALSE;
 
   /**
+   * Static cache of entity revisions, keyed by entity revision ID.
+   *
+   * @var array
+   */
+  protected $entityRevisions = [];
+
+  /**
    * The entity manager.
    *
    * @var \Drupal\Core\Entity\EntityManagerInterface
@@ -220,7 +227,62 @@ public function finalizePurge(FieldStorageDefinitionInterface $storage_definitio
   /**
    * {@inheritdoc}
    */
+  public function load($id) {
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    $entity = parent::load($id);
+
+    // If there is already an entry in the static entity revisions cache we
+    // return a reference to the already loaded entity object.
+    //
+    // @todo find a better way to determine the default revision id without
+    // having to load the entity object from the storage, then check if there
+    // is already an entry in the static entity revisions cache for it and if
+    // not load the entity from the storage.
+    if ($this->entityType->isStaticallyCacheable() && $entity->getRevisionId()) {
+      // If the default revision is not present in the static entity revision
+      // cache we add it and return the entity.
+      if (!isset($this->entityRevisions[$entity->getRevisionId()])) {
+        $this->entityRevisions[$entity->getRevisionId()] = $entity;
+      }
+      return $this->entityRevisions[$entity->getRevisionId()];
+    }
+
+    return $entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function loadRevision($revision_id) {
+    if ($this->entityType->isStaticallyCacheable()) {
+      if (!isset($this->entityRevisions[$revision_id])) {
+        if ($revision = $this->getRevisionFromPersistentCache($revision_id)) {
+          $this->entityRevisions[$revision_id] = $revision;
+        }
+        else {
+          $revision = $this->doLoadRevision($revision_id);
+          $this->entityRevisions[$revision_id] = $revision;
+          if ($revision->isDefaultRevision()) {
+            $this->setPersistentCache([$revision->id() => $revision]);
+          }
+        }
+      }
+      return $this->entityRevisions[$revision_id];
+    }
+
+    return $this->doLoadRevision($revision_id);
+  }
+
+  /**
+   * Load a specific entity revision.
+   *
+   * @param int|string $revision_id
+   *   The revision id.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface|null
+   *   The specified entity revision or NULL if not found.
+   */
+  protected function doLoadRevision($revision_id) {
     $revision = $this->doLoadRevisionFieldItems($revision_id);
 
     if ($revision) {
@@ -312,6 +374,15 @@ protected function doPostSave(EntityInterface $entity, $update) {
     if ($this->entityType->isRevisionable()) {
       $entity->setNewRevision(FALSE);
     }
+
+    // Update the original revision id to the new value.
+    $entity->resetOriginalRevisionId();
+
+    // Set the static entity revision cache reference, which has been removed
+    // by the parent class call to ::resetCache.
+    if ($this->entityType->isStaticallyCacheable() && $entity->getOriginalRevisionId()) {
+      $this->entityRevisions[$entity->getOriginalRevisionId()] = $entity;
+    }
   }
 
   /**
@@ -588,6 +659,29 @@ protected function getFromPersistentCache(array &$ids = NULL) {
   }
 
   /**
+   * Gets entity from the persistent cache backend by revision id.
+   *
+   * @param int|null $revision_id
+   *   If not empty, return the entity that match these revision ID.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface|null
+   *   The entity from the persistent cache or NULL if not present.
+   */
+  protected function getRevisionFromPersistentCache($revision_id = NULL) {
+    $revision = NULL;
+    if (!$this->entityType->isPersistentlyCacheable() || empty($revision_id)) {
+      return $revision;
+    }
+    // Build the list of cache entries to retrieve.
+    $cid = $this->buildRevisionCacheId($revision_id);
+    if ($cache = $this->cacheBackend->get($cid)) {
+      // Get the entity that was found in the cache.
+      $revision = $cache->data;
+    }
+    return $revision;
+  }
+
+  /**
    * Stores entities in the persistent cache backend.
    *
    * @param \Drupal\Core\Entity\ContentEntityInterface[] $entities
@@ -604,6 +698,9 @@ protected function setPersistentCache($entities) {
     );
     foreach ($entities as $id => $entity) {
       $this->cacheBackend->set($this->buildCacheId($id), $entity, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
+      if ($revision_id = $entity->getRevisionId()) {
+        $this->cacheBackend->set($this->buildRevisionCacheId($revision_id), $entity, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
+      }
     }
   }
 
@@ -612,24 +709,71 @@ protected function setPersistentCache($entities) {
    */
   public function resetCache(array $ids = NULL) {
     if ($ids) {
-      $cids = array();
+      $cids = [];
+      $revision_ids = [];
       foreach ($ids as $id) {
+        if (isset($this->entities[$id])) {
+          $original_revision_id = $this->entities[$id]->getOriginalRevisionId();
+          $revision_id = $this->entities[$id]->getRevisionId();
+          $revision_ids[$original_revision_id] = $original_revision_id;
+          $revision_ids[$revision_id] = $revision_id;
+        }
         unset($this->entities[$id]);
         $cids[] = $this->buildCacheId($id);
       }
+      $this->resetRevisionCache($revision_ids, TRUE);
       if ($this->entityType->isPersistentlyCacheable()) {
         $this->cacheBackend->deleteMultiple($cids);
       }
     }
     else {
-      $this->entities = array();
+      $this->entities = [];
+      $this->entityRevisions = [];
       if ($this->entityType->isPersistentlyCacheable()) {
-        Cache::invalidateTags(array($this->entityTypeId . '_values'));
+        Cache::invalidateTags([$this->entityTypeId . '_values']);
+      }
+    }
+  }
+
+  /**
+   * Resets the internal, static entity revision cache.
+   *
+   * @param $revision_ids
+   *   The revision cache will be reset for the entities with the given
+   *   revision ids.
+   */
+  protected function resetRevisionCache(array $revision_ids) {
+    if ($revision_ids) {
+      $cids = [];
+      foreach ($revision_ids as $revision_id) {
+        unset($this->entityRevisions[$revision_id]);
+        $cids[] = $this->buildRevisionCacheId($revision_id);
+      }
+      if ($this->entityType->isPersistentlyCacheable()) {
+        $this->cacheBackend->deleteMultiple($cids);
       }
     }
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function loadRevisionUnchanged($revision_id) {
+    // If the revision for the given revision id is present in the static cache
+    // and it represents a default revision, then delete the entity and the
+    // revision cache for it, otherwise there will be no entity cache and in
+    // this case we have to delete only the revision cache.
+    if (isset($this->entityRevisions[$revision_id]) && $this->entityRevisions[$revision_id]->isDefaultRevision()) {
+      $this->resetCache([$this->entityRevisions[$revision_id]->id()]);
+    }
+    else {
+      $this->resetRevisionCache([$revision_id]);
+    }
+
+    return $this->loadRevision($revision_id);
+  }
+
+  /**
    * Builds the cache ID for the passed in entity ID.
    *
    * @param int $id
@@ -642,4 +786,17 @@ protected function buildCacheId($id) {
     return "values:{$this->entityTypeId}:$id";
   }
 
+  /**
+   * Builds the cache ID for the passed in entity revision ID.
+   *
+   * @param int $revision_id
+   *   Entity revision ID for which the cache ID should be built.
+   *
+   * @return string
+   *   Cache ID that can be passed to the cache backend.
+   */
+  protected function buildRevisionCacheId($revision_id) {
+    return "values:{$this->entityTypeId}:revision:$revision_id";
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
index e973c39..cd79bbd 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
@@ -13,6 +13,41 @@
 interface ContentEntityStorageInterface extends EntityStorageInterface {
 
   /**
+   * Load a specific entity revision.
+   *
+   * @param int|string $revision_id
+   *   The revision id.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface|null
+   *   The specified entity revision or NULL if not found.
+   */
+  public function loadRevision($revision_id);
+
+  /**
+   * Loads an unchanged entity by revision id from the database.
+   *
+   * @param mixed $revision_id
+   *   The revision ID of the entity to load.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface|null
+   *   The unchanged entity, or NULL if the entity cannot be loaded.
+   *
+   * @todo Remove this method once we have a reliable way to retrieve the
+   *   unchanged entity from the entity object.
+   */
+  public function loadRevisionUnchanged($revision_id);
+
+  /**
+   * Delete a specific entity revision.
+   *
+   * A revision can only be deleted if it's not the currently active one.
+   *
+   * @param int $revision_id
+   *   The revision id.
+   */
+  public function deleteRevision($revision_id);
+
+  /**
    * Constructs a new entity translation object, without permanently saving it.
    *
    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageBase.php b/core/lib/Drupal/Core/Entity/EntityStorageBase.php
index 31bf8ed..6548165 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageBase.php
@@ -19,7 +19,7 @@
    *
    * @var array
    */
-  protected $entities = array();
+  protected $entities = [];
 
   /**
    * Entity type ID for this storage.
@@ -480,6 +480,12 @@ protected function doPostSave(EntityInterface $entity, $update) {
     $entity->setOriginalId($entity->id());
 
     unset($entity->original);
+
+    // Set the static entity cache reference, which has been removed by the
+    // call to ::resetCache.
+    if ($this->entityType->isStaticallyCacheable()) {
+      $this->entities[$entity->id()] = $entity;
+    }
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
index f7b4b4a..a00f088 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
@@ -77,27 +77,6 @@ public function load($id);
   public function loadUnchanged($id);
 
   /**
-   * Load a specific entity revision.
-   *
-   * @param int|string $revision_id
-   *   The revision id.
-   *
-   * @return \Drupal\Core\Entity\EntityInterface|null
-   *   The specified entity revision or NULL if not found.
-   */
-  public function loadRevision($revision_id);
-
-  /**
-   * Delete a specific entity revision.
-   *
-   * A revision can only be deleted if it's not the currently active one.
-   *
-   * @param int $revision_id
-   *   The revision id.
-   */
-  public function deleteRevision($revision_id);
-
-  /**
    * Load entities by their property values.
    *
    * @param array $values
diff --git a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
index e696116..b9dbda3 100644
--- a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
@@ -18,6 +18,27 @@ class KeyValueContentEntityStorage extends KeyValueEntityStorage implements Cont
   /**
    * {@inheritdoc}
    */
+  public function loadRevision($revision_id) {
+    // @todo
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadRevisionUnchanged($revision_id) {
+    // @todo
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteRevision($revision_id) {
+    // @todo
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []) {
     // @todo Complete the content entity storage implementation in
     //   https://www.drupal.org/node/2618436.
diff --git a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueEntityStorage.php b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueEntityStorage.php
index 890a9b4..3bf9f18 100644
--- a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueEntityStorage.php
@@ -131,20 +131,6 @@ public function doLoadMultiple(array $ids = NULL) {
   /**
    * {@inheritdoc}
    */
-  public function loadRevision($revision_id) {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteRevision($revision_id) {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function doDelete($entities) {
     $entity_ids = array_keys($entities);
     $this->keyValueStore->deleteMultiple($entity_ids);
diff --git a/core/lib/Drupal/Core/Entity/RevisionableInterface.php b/core/lib/Drupal/Core/Entity/RevisionableInterface.php
index f9433bc..d68ce7a 100644
--- a/core/lib/Drupal/Core/Entity/RevisionableInterface.php
+++ b/core/lib/Drupal/Core/Entity/RevisionableInterface.php
@@ -45,6 +45,29 @@ public function setNewRevision($value = TRUE);
   public function getRevisionId();
 
   /**
+   * Gets the original revision identifier of the entity.
+   *
+   * After calling ::setNewRevision, the revision identifier will be unset to
+   * enforce the creation of a new revision identifier on save and
+   * ::getRevisionId will not be able to return the revision identifier, for
+   * which the entity has been loaded, but ::getOriginalRevisionId will.
+   *
+   * @return
+   *   The original revision identifier of the entity, or NULL if the entity
+   *   does not have a revision identifier.
+   */
+  public function getOriginalRevisionId();
+
+  /**
+   * Resets the original revision identifier after the entity got a new one.
+   *
+   * After the entity has been saved, the storage should call this function to
+   * set the original revision identifier to the new one, the entity received
+   * after it has been saved.
+   */
+  public function resetOriginalRevisionId();
+
+  /**
    * Checks if this entity is the default revision.
    *
    * @param bool $new_value
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityStaticCacheTest.php b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityStaticCacheTest.php
new file mode 100644
index 0000000..7c40ba1
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityStaticCacheTest.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\KernelTests\Core\Entity\ContentEntityStaticCacheTest.
+ */
+
+namespace Drupal\KernelTests\Core\Entity;
+
+use Drupal\entity_test\Entity\EntityTestRev;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the entity static cache when used by content entities.
+ *
+ * @group config
+ */
+class ContentEntityStaticCacheTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['entity_test', 'user'];
+
+  /**
+   * The entity ID of the entity under test.
+   *
+   * @var string
+   */
+  protected $entityId;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('entity_test_rev');
+
+    $entity = EntityTestRev::create([
+      'name' => 'test'
+    ]);
+    $entity->save();
+    $this->entityId = $entity->id();
+  }
+
+  /**
+   * Tests the static entity cache.
+   */
+  public function testStaticEntityCache() {
+    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+    $storage = \Drupal::entityTypeManager()->getStorage('entity_test_rev');
+
+    // Test load.
+    $entity_load_first = $storage->load($this->entityId);
+    $entity_load_second = $storage->load($this->entityId);
+    $this->assertSame($entity_load_first, $entity_load_second, 'Calling ContentEntityStorageBase::load multiple times returns a reference to the same entity object.');
+
+    $entity_unchanged_first = $storage->loadUnchanged($this->entityId);
+    $entity_unchanged_second = $storage->loadUnchanged($this->entityId);
+    $this->assertNotSame($entity_unchanged_first, $entity_unchanged_second, 'Calling ContentEntityStorageBase::loadUnchanged multiple times returns each time a new entity object.');
+    $this->assertNotSame($entity_load_first, $entity_unchanged_first, 'ContentEntityStorageBase::load and ContentEntityStorageBase::loadUnchanged return different entity objects.');
+
+    // Test loadRevision.
+    $entity_rev_id = $entity_load_first->getRevisionId();
+    $entity_revision_first = $storage->loadRevision($entity_rev_id);
+    $entity_revision_second = $storage->loadRevision($entity_rev_id);
+    $this->assertSame($entity_revision_first, $entity_revision_second, 'Calling ContentEntityStorageBase::loadRevision multiple times returns a reference to the same entity object.');
+
+    $entity_revision_unchanged_first = $storage->loadRevisionUnchanged($entity_rev_id);
+    $entity_revision_unchanged_second = $storage->loadRevisionUnchanged($entity_rev_id);
+    $this->assertNotSame($entity_revision_unchanged_first, $entity_revision_unchanged_second, 'Calling ContentEntityStorageBase::loadRevisionUnchanged multiple times returns each time a new entity object.');
+    $this->assertNotSame($entity_revision_first, $entity_revision_unchanged_first, 'ContentEntityStorageBase::loadRevision and ContentEntityStorageBase::loadRevisionUnchanged return different entity objects.');
+
+    // Test loading a default revision with load and loadRevision.
+    $this->assertSame($entity_load_first, $entity_revision_first, 'ContentEntityStorageBase::load and ContentEntityStorageBase::loadRevision return a reference to the same entity object when loading a default revision.');
+  }
+
+}
