diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index 9d6b8d64f5..06ff5ad123 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -21,6 +21,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
@@ -35,6 +42,16 @@
   protected $cacheBackend;
 
   /**
+   * Whether the static cache should be ignored when loading an entity.
+   *
+   * This property will be set by ::loadRevisionUnchanged() in order for
+   * ::loadRevision() to load the entity without using the static entity cache.
+   *
+   * @var bool
+   */
+  protected $ignoreStaticCache;
+
+  /**
    * Constructs a ContentEntityStorageBase object.
    *
    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
@@ -215,13 +232,82 @@ 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 ($entity && $this->entityType->isStaticallyCacheable() && $this->entityType->isRevisionable()) {
+      // If the default revision is not present in the static entity revision
+      // cache we add it and return the entity.
+      $revision_id = $entity->getRevisionId();
+      if (!$this->getFromStaticEntityRevisionCache($revision_id)) {
+        $this->setStaticEntityRevisionCache($revision_id, $entity);
+      }
+      return $this->getFromStaticEntityRevisionCache($revision_id);
+    }
+
+    return $entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function loadRevision($revision_id) {
-    $revision = $this->doLoadRevisionFieldItems($revision_id);
+    $revision = NULL;
+
+    if (!isset($this->ignoreStaticCache)) {
+      if ($this->entityType->isStaticallyCacheable()) {
+        $revision = $this->getFromStaticEntityRevisionCache($revision_id);
+      }
+
+      if (!$revision && $this->entityType->isPersistentlyCacheable()) {
+        $revision = $this->getRevisionFromPersistentCache($revision_id);
+        if ($revision) {
+          $entities = [$revision->id() => $revision];
+          $this->postLoad($entities);
+          $this->setStaticEntityRevisionCache($revision_id, $revision);
+          if ($revision->isDefaultRevision()) {
+            $this->setStaticCache($entities);
+          }
+        }
+      }
+    }
 
-    if ($revision) {
+    return $revision ?: $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) {
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
+    if ($revision = $this->doLoadRevisionFieldItems($revision_id)) {
       $entities = [$revision->id() => $revision];
       $this->invokeStorageLoadHook($entities);
+      if ($revision->isDefaultRevision()) {
+        $this->setPersistentCache($entities);
+      }
       $this->postLoad($entities);
+
+      if (!isset($this->ignoreStaticCache)) {
+        if ($revision->isDefaultRevision()) {
+          $this->setStaticCache($entities);
+        }
+        $this->setStaticEntityRevisionCache($revision_id, $revision);
+      }
     }
 
     return $revision;
@@ -323,6 +409,19 @@ protected function doPostSave(EntityInterface $entity, $update) {
       $this->invokeTranslationHooks($entity);
     }
 
+    if ($this->entityType->isRevisionable()) {
+      // If a non-default revision has been loaded it has been statically only
+      // in the entity revision cache, which means that the parent class call
+      // in ::doPostSave to ::resetCache will not be able to reset the static
+      // revision cache as it is only calling the function with the entity id,
+      // but as for this entity id there will be no entity cache entry we'll
+      // not be able to retrieve the revision id and remove its static cache
+      // there.
+      // @todo consider adding an optional entity parameter to ::resetCache, as
+      // in this case we'll not need this logic here.
+      $this->resetRevisionCache([$entity->getRevisionId(), $entity->getLoadedRevisionId()]);
+    }
+
     parent::doPostSave($entity, $update);
 
     // The revision is stored, it should no longer be marked as new now.
@@ -628,6 +727,38 @@ 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) {
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
+    $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;
+    }
+
+    // We might have saved already a new entity revision as the default one so
+    // on fetching from the persistent cache we have to update the
+    // $isDefaultRevision property of the entity revision.
+    if ($revision && $revision->isDefaultRevision() && ($revision_id != $this->getDefaultRevisionId($revision->id()))) {
+      $revision->isDefaultRevision(FALSE);
+    }
+
+    return $revision;
+  }
+
+  /**
    * Stores entities in the persistent cache backend.
    *
    * @param \Drupal\Core\Entity\ContentEntityInterface[] $entities
@@ -644,6 +775,9 @@ protected function setPersistentCache($entities) {
     ];
     foreach ($entities as $id => $entity) {
       $this->cacheBackend->set($this->buildCacheId($id), $entity, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
+      if ($this->entityType->isRevisionable() && $entity->isDefaultRevision()) {
+        $this->cacheBackend->set($this->buildRevisionCacheId($entity->getRevisionId()), $entity, CacheBackendInterface::CACHE_PERMANENT, $cache_tags);
+      }
     }
   }
 
@@ -653,6 +787,9 @@ protected function setPersistentCache($entities) {
   public function loadUnchanged($id) {
     $ids = [$id];
 
+    // Reset the static entity revision cache.
+    $revision_ids = $this->getRevisionIDsOfStaticallyCachedEntities($ids);
+    $this->resetStaticRevisionCache($revision_ids);
     // The cache invalidation in the parent has the side effect that loading the
     // same entity again during the save process (for example in
     // hook_entity_presave()) will load the unchanged entity. Simulate this
@@ -693,16 +830,19 @@ public function loadUnchanged($id) {
   public function resetCache(array $ids = NULL) {
     if ($ids) {
       $cids = [];
+      $revision_ids = $this->getRevisionIDsOfStaticallyCachedEntities($ids);
       foreach ($ids as $id) {
         unset($this->entities[$id]);
         $cids[] = $this->buildCacheId($id);
       }
+      $this->resetRevisionCache($revision_ids);
       if ($this->entityType->isPersistentlyCacheable()) {
         $this->cacheBackend->deleteMultiple($cids);
       }
     }
     else {
       $this->entities = [];
+      $this->entityRevisions = [];
       if ($this->entityType->isPersistentlyCacheable()) {
         Cache::invalidateTags([$this->entityTypeId . '_values']);
       }
@@ -710,6 +850,124 @@ public function resetCache(array $ids = NULL) {
   }
 
   /**
+   * Returns the revision ids of statically cached entities.
+   *
+   * @param $ids
+   *   (optional) If specified, the revision ids will be retrieved of the
+   *   statically cached entities with the given ids only, otherwise the
+   *   revision ids of all statically cached entities will be retrieved.
+   *
+   * @return array
+   *   The revision ids.
+   */
+  protected function getRevisionIDsOfStaticallyCachedEntities(array $ids = NULL) {
+    $revision_ids = [];
+    if (!$this->entityType->isRevisionable()) {
+      return $revision_ids;
+    }
+    $entities = isset($ids) ? array_intersect_key($this->entities, array_flip($ids)) : $this->entities;
+    foreach ($entities as $entity) {
+      $original_revision_id = $entity->getLoadedRevisionId();
+      $revision_id = $entity->getRevisionId();
+      $revision_ids[$original_revision_id] = $original_revision_id;
+      $revision_ids[$revision_id] = $revision_id;
+    }
+    return $revision_ids;
+  }
+
+  /**
+   * Resets the static and persistent entity revision cache.
+   *
+   * @param $revision_ids
+   *   The revision ids to reset the revision cache for.
+   */
+  protected function resetRevisionCache(array $revision_ids) {
+    $this->resetStaticRevisionCache($revision_ids);
+    $this->resetPersistentRevisionCache($revision_ids);
+  }
+
+  /**
+   * Resets the static entity revision cache.
+   *
+   * @param $revision_ids
+   *   The revision ids to reset the static revision cache for.
+   */
+  protected function resetStaticRevisionCache(array $revision_ids) {
+    if (!$this->entityType->isStaticallyCacheable()) {
+      return;
+    }
+    foreach ($revision_ids as $revision_id) {
+      unset($this->entityRevisions[$revision_id]);
+    }
+  }
+
+  /**
+   * Resets the persistent entity revision cache.
+   *
+   * @param $revision_ids
+   *   The revision ids to reset the persistent revision cache for.
+   */
+  protected function resetPersistentRevisionCache(array $revision_ids) {
+    if (!$this->entityType->isPersistentlyCacheable()) {
+      return;
+    }
+    $cids = [];
+    foreach ($revision_ids as $revision_id) {
+      $cids[] = $this->buildRevisionCacheId($revision_id);
+    }
+    $this->cacheBackend->deleteMultiple($cids);
+  }
+
+  /**
+   * Gets entities from the static entity revision cache.
+   *
+   * @param int $revision_id
+   *   The entity revision id, for which the entity should be loaded from the
+   *   static entity revision cache.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface|NULL
+   *   The entity from the entity revision cache or NULL if it is not present.
+   */
+  protected function getFromStaticEntityRevisionCache($revision_id) {
+    return $this->entityType->isStaticallyCacheable() && isset($this->entityRevisions[$revision_id]) ? $this->entityRevisions[$revision_id] : NULL;
+  }
+
+  /**
+   * Stores entities in the static entity revision cache.
+   *
+   * @param int $revision_id
+   *   The entity revision id, for which the entity should be stored in the
+   *   static entity revision cache.
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The entity to store in the static entity revision cache.
+   */
+  protected function setStaticEntityRevisionCache($revision_id, ContentEntityInterface $entity) {
+    if ($this->entityType->isStaticallyCacheable()) {
+      $this->entityRevisions[$revision_id] = $entity;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadRevisionUnchanged($revision_id) {
+    // Load the revision by ignoring the static entity and entity revision
+    // cache.
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
+    if ($revision = $this->getRevisionFromPersistentCache($revision_id)) {
+      $entities = [$revision->id() => $revision];
+      $this->postLoad($entities);
+    }
+    else {
+      $this->ignoreStaticCache = TRUE;
+      $revision = $this->loadRevision($revision_id);
+      unset($this->ignoreStaticCache);
+    }
+
+    return $revision;
+  }
+
+  /**
    * Builds the cache ID for the passed in entity ID.
    *
    * @param int $id
@@ -722,4 +980,36 @@ 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";
+  }
+
+  /**
+   * Fetches the current default revision id.
+   *
+   * @param int $id
+   *   The entity id.
+   *
+   * @return int|null
+   *   The default revision id.
+   */
+  protected function getDefaultRevisionId($id) {
+    $result = NULL;
+    if ($this->entityType->isRevisionable()) {
+      $result = $this->getQuery()
+        ->condition($this->entityType->getKey('id'), $id)
+        ->execute();
+    }
+    return $result ? key($result) : NULL;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
index 47e058d8e1..a9bdbff623 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
@@ -8,6 +8,20 @@
 interface ContentEntityStorageInterface extends EntityStorageInterface {
 
   /**
+   * Loads an unchanged entity by revision id from the database.
+   *
+   * @param int $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);
+
+  /**
    * Constructs a new entity translation object, without permanently saving it.
    *
    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
diff --git a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
index c42e7c0de5..8ce3fb4632 100644
--- a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
@@ -13,9 +13,33 @@ class KeyValueContentEntityStorage extends KeyValueEntityStorage implements Cont
   /**
    * {@inheritdoc}
    */
+  public function loadRevision($revision_id) {
+    // @todo Complete the content entity storage implementation in
+    // https://www.drupal.org/node/2618436.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadRevisionUnchanged($revision_id) {
+    // @todo Complete the content entity storage implementation in
+    // https://www.drupal.org/node/2618436.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteRevision($revision_id) {
+    // @todo Complete the content entity storage implementation in
+    // https://www.drupal.org/node/2618436.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []) {
     // @todo Complete the content entity storage implementation in
-    //   https://www.drupal.org/node/2618436.
+    // https://www.drupal.org/node/2618436.
   }
 
 }
diff --git a/core/modules/content_moderation/src/Entity/ContentModerationState.php b/core/modules/content_moderation/src/Entity/ContentModerationState.php
index 5b1c250679..f474433d10 100644
--- a/core/modules/content_moderation/src/Entity/ContentModerationState.php
+++ b/core/modules/content_moderation/src/Entity/ContentModerationState.php
@@ -155,7 +155,7 @@ public static function getCurrentUserId() {
   public function save() {
     $related_entity = \Drupal::entityTypeManager()
       ->getStorage($this->content_entity_type_id->value)
-      ->loadRevision($this->content_entity_revision_id->value);
+      ->loadRevisionUnchanged($this->content_entity_revision_id->value);
     if ($related_entity instanceof TranslatableInterface) {
       $related_entity = $related_entity->getTranslation($this->activeLangcode);
     }
diff --git a/core/modules/content_moderation/src/EntityOperations.php b/core/modules/content_moderation/src/EntityOperations.php
index 3f66100581..5412615eca 100644
--- a/core/modules/content_moderation/src/EntityOperations.php
+++ b/core/modules/content_moderation/src/EntityOperations.php
@@ -263,7 +263,10 @@ public function entityView(array &$build, EntityInterface $entity, EntityViewDis
    *   TRUE if the default revision is published. FALSE otherwise.
    */
   protected function isDefaultRevisionPublished(EntityInterface $entity, WorkflowInterface $workflow) {
-    $default_revision = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->load($entity->id());
+    // We have to load the unchanged entity for the default revision to ensure
+    // that we are not retrieving a modified entity from the static entity
+    // cache.
+    $default_revision = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id());
 
     // Ensure we are checking all translations of the default revision.
     if ($default_revision instanceof TranslatableInterface && $default_revision->isTranslatable()) {
diff --git a/core/modules/content_moderation/src/ModerationInformation.php b/core/modules/content_moderation/src/ModerationInformation.php
index c20be5291f..ac9724bfa2 100644
--- a/core/modules/content_moderation/src/ModerationInformation.php
+++ b/core/modules/content_moderation/src/ModerationInformation.php
@@ -74,7 +74,7 @@ public function shouldModerateEntitiesOfBundle(EntityTypeInterface $entity_type,
    */
   public function getLatestRevision($entity_type_id, $entity_id) {
     if ($latest_revision_id = $this->getLatestRevisionId($entity_type_id, $entity_id)) {
-      return $this->entityTypeManager->getStorage($entity_type_id)->loadRevision($latest_revision_id);
+      return $this->entityTypeManager->getStorage($entity_type_id)->loadRevisionUnchanged($latest_revision_id);
     }
   }
 
diff --git a/core/modules/content_moderation/src/ModerationInformationInterface.php b/core/modules/content_moderation/src/ModerationInformationInterface.php
index 862987f8d8..ae9a24dbf1 100644
--- a/core/modules/content_moderation/src/ModerationInformationInterface.php
+++ b/core/modules/content_moderation/src/ModerationInformationInterface.php
@@ -48,7 +48,7 @@ public function canModerateEntitiesOfEntityType(EntityTypeInterface $entity_type
   public function shouldModerateEntitiesOfBundle(EntityTypeInterface $entity_type, $bundle);
 
   /**
-   * Loads the latest revision of a specific entity.
+   * Loads the unmodified latest revision of a specific entity.
    *
    * @param string $entity_type_id
    *   The entity type ID.
diff --git a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
index 2d93f5a7c2..833ee97f9a 100644
--- a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
+++ b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
@@ -69,7 +69,12 @@ protected function loadContentModerationStateRevision(ContentEntityInterface $en
     }
 
     /** @var \Drupal\content_moderation\ContentModerationStateInterface $content_moderation_state */
-    $content_moderation_state = $content_moderation_storage->loadRevision(key($revisions));
+    // In the case the content moderation state entity is edited and saved
+    // separately from the related entity it will trigger saving of the related
+    // entity and therefor the content moderation state will be loaded here
+    // again and we have to make sure we will load the unchanged entity and not
+    // load the already modified one from the static entity cache.
+    $content_moderation_state = $content_moderation_storage->loadRevisionUnchanged(key($revisions));
     if ($entity->getEntityType()->hasKey('langcode')) {
       $langcode = $entity->language()->getId();
       if (!$content_moderation_state->hasTranslation($langcode)) {
diff --git a/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php b/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php
index f68c2bea1f..920f0feed1 100644
--- a/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php
+++ b/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\migrate\Unit\destination;
 
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\ContentEntityStorageInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\migrate\Plugin\MigrationInterface;
 use Drupal\migrate\Plugin\migrate\destination\EntityRevision as RealEntityRevision;
@@ -47,7 +48,7 @@ protected function setUp() {
 
     // Setup mocks to be used when creating a revision destination.
     $this->migration = $this->prophesize(MigrationInterface::class);
-    $this->storage = $this->prophesize('\Drupal\Core\Entity\EntityStorageInterface');
+    $this->storage = $this->prophesize(ContentEntityStorageInterface::class);
     $this->entityManager = $this->prophesize('\Drupal\Core\Entity\EntityManagerInterface');
     $this->fieldTypeManager = $this->prophesize('\Drupal\Core\Field\FieldTypePluginManagerInterface');
   }
@@ -60,7 +61,7 @@ protected function setUp() {
   public function testGetEntityDestinationValues() {
     $destination = $this->getEntityRevisionDestination([]);
     // Return a dummy because we don't care what gets called.
-    $entity = $this->prophesize('\Drupal\Core\Entity\EntityInterface')
+    $entity = $this->prophesize(ContentEntityInterface::class)
       ->willImplement('\Drupal\Core\Entity\RevisionableInterface');
     // Assert that the first ID from the destination values is used to load the
     // entity.
diff --git a/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
index 02a5ce64c8..c2c5069b85 100644
--- a/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
+++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\views\Unit\Plugin\query;
 
+use Drupal\Core\Entity\ContentEntityStorageInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityType;
@@ -212,8 +213,8 @@ protected function setupEntityTypes($entities_by_type = [], $entity_revisions_by
 
     // Setup the loading of entities and entity revisions.
     $entity_storages = [
-      'first' => $this->prophesize(EntityStorageInterface::class),
-      'second' => $this->prophesize(EntityStorageInterface::class),
+      'first' => $this->prophesize(ContentEntityStorageInterface::class),
+      'second' => $this->prophesize(ContentEntityStorageInterface::class),
     ];
 
     foreach ($entities_by_type as $entity_type_id => $entities) {
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 0000000000..f1f81d72d1
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntityStaticCacheTest.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Entity;
+
+use Drupal\Core\Cache\Cache;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the entity static cache when used by content entities.
+ *
+ * @group Entity
+ */
+class ContentEntityStaticCacheTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['entity_test', 'user'];
+
+  /**
+   * A non-revisionable entity type ID to test with.
+   *
+   * @var string
+   */
+  protected $nonRevEntityTypeId = 'entity_test_mul';
+
+  /**
+   *  A revisionable entity type ID to test with.
+   *
+   * @var string
+   */
+  protected $revEntityTypeId = 'entity_test_mulrev';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // The user entity is required, as the content entities we are testing with
+    // have an entity reference field with the user entity type as as target.
+    $this->installEntitySchema('user');
+    $this->installEntitySchema($this->nonRevEntityTypeId);
+    $this->installEntitySchema($this->revEntityTypeId);
+  }
+
+  /**
+   * Tests that loadUnchanged will not return the same entity object reference.
+   */
+  public function testLoadUnchanged() {
+    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
+    $entity_type_manager = $this->container->get('entity_type.manager');
+
+    $non_rev_entity_type = $entity_type_manager->getDefinition($this->nonRevEntityTypeId);
+    $this->assertTrue($non_rev_entity_type->isStaticallyCacheable());
+    $this->assertTrue($non_rev_entity_type->isPersistentlyCacheable());
+    $this->doTestLoadUnchanged($this->nonRevEntityTypeId);
+
+    $rev_entity_type = $entity_type_manager->getDefinition($this->revEntityTypeId);
+    $this->assertTrue($rev_entity_type->isStaticallyCacheable());
+    $this->assertTrue($rev_entity_type->isPersistentlyCacheable());
+    $this->assertTrue($rev_entity_type->isRevisionable());
+    $this->doTestLoadUnchanged($this->revEntityTypeId);
+  }
+
+  /**
+   * Tests Storage::loadUnchanged returning different entity object reference.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID to test Storage::loadUnchanged() with.
+   */
+  protected function doTestLoadUnchanged($entity_type_id) {
+    foreach ([FALSE, TRUE] as $invalidate_entity_cache) {
+      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+      $storage = $this->container->get('entity_type.manager')
+        ->getStorage($entity_type_id);
+
+      $entity = $storage->create();
+      $entity->save();
+
+      $entity = $storage->load($entity->id());
+      // Invalidating the entity cache will lead to not retrieving the entity
+      // from the persistent entity cache. This simulates e.g. a behavior where
+      // in an entity insert hook a field config is created and saved and then
+      // the cache tag "entity_field_info" will be invalidated leading to
+      // invalidating the entities in the entity cache, which will prevent
+      // loadUnchanged from retrieving the entity from the persistent cache,
+      // which will test that the static entity cache has been reset properly,
+      // otherwise if not then the same entity object reference will be
+      // returned.
+      if ($invalidate_entity_cache) {
+        Cache::invalidateTags(['entity_field_info']);
+      }
+      $unchanged = $storage->loadUnchanged($entity->id());
+      $message = $invalidate_entity_cache ? 'loadUnchanged returns a different entity object reference when the entity cache is invalidated before that.' : 'loadUnchanged returns a different entity object reference when the entity cache is not invalidated before that.';
+      $this->assertNotSame($entity, $unchanged, $message);
+    }
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php b/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php
index 23ac69fd7f..e55f2581c8 100644
--- a/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php
+++ b/core/tests/Drupal/Tests/Core/ParamConverter/EntityRevisionParamConverterTest.php
@@ -2,9 +2,9 @@
 
 namespace Drupal\Tests\Core\ParamConverter;
 
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityRepositoryInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\ContentEntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\ParamConverter\EntityRevisionParamConverter;
 use Drupal\Tests\UnitTestCase;
@@ -65,8 +65,8 @@ public function testApplyingRoute() {
    * @covers ::convert
    */
   public function testConvert() {
-    $entity = $this->prophesize(EntityInterface::class)->reveal();
-    $storage = $this->prophesize(EntityStorageInterface::class);
+    $entity = $this->prophesize(ContentEntityInterface::class)->reveal();
+    $storage = $this->prophesize(ContentEntityStorageInterface::class);
     $storage->loadRevision(1)->willReturn($entity);
 
     $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
