diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 5376644..38011f5 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -334,6 +334,16 @@ public function isDefaultRevision($new_value = NULL) {
   /**
    * {@inheritdoc}
    */
+  public function isLatestRevision() {
+    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+    $storage = $this->entityTypeManager()->getStorage($this->getEntityTypeId());
+
+    return $this->getLoadedRevisionId() == $storage->getLatestRevisionId($this->id());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isRevisionTranslationAffected() {
     return $this->hasField($this->revisionTranslationAffectedKey) ? $this->get($this->revisionTranslationAffectedKey)->value : TRUE;
   }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index 2b06b92..1931ad6 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -169,6 +169,47 @@ public function createTranslation(ContentEntityInterface $entity, $langcode, arr
   /**
    * {@inheritdoc}
    */
+  public function getLatestRevisionId($entity_id) {
+    if (!$this->entityType->isRevisionable()) {
+      return NULL;
+    }
+
+    $result = $this->getQuery()
+      ->latestRevision()
+      ->condition($this->entityType->getKey('id'), $entity_id)
+      ->accessCheck(FALSE)
+      ->execute();
+
+    return key($result);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLatestAffectedRevisionId($entity_id, $langcode) {
+    if (!$this->entityType->isRevisionable()) {
+      return NULL;
+    }
+
+    if (!$this->entityType->isTranslatable()) {
+      return $this->getLatestRevisionId($entity_id);
+    }
+
+    $result = $this->getQuery()
+      ->allRevisions()
+      ->condition($this->entityType->getKey('id'), $entity_id)
+      ->condition($this->entityType->getKey('revision_translation_affected'), 1, '=', $langcode)
+      ->range(0, 1)
+      ->sort($this->entityType->getKey('revision'), 'DESC')
+      ->accessCheck(FALSE)
+      ->execute();
+
+    return key($result);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $storage_definition) {}
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
index eb979c7..678937b 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
@@ -5,7 +5,7 @@
 /**
  * A storage that supports content entity types.
  */
-interface ContentEntityStorageInterface extends EntityStorageInterface {
+interface ContentEntityStorageInterface extends EntityStorageInterface, RevisionableStorageInterface {
 
   /**
    * Constructs a new entity translation object, without permanently saving it.
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
index 9f50674..5ef994a 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
@@ -79,6 +79,11 @@ public function loadUnchanged($id);
    *
    * @return \Drupal\Core\Entity\EntityInterface|null
    *   The specified entity revision or NULL if not found.
+   *
+   * @todo Deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0.
+   *   Use \Drupal\Core\Entity\RevisionableStorageInterface instead.
+   *
+   * @see https://www.drupal.org/node/2926958
    */
   public function loadRevision($revision_id);
 
@@ -89,6 +94,11 @@ public function loadRevision($revision_id);
    *
    * @param int $revision_id
    *   The revision id.
+   *
+   * @todo Deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0.
+   *   Use \Drupal\Core\Entity\RevisionableStorageInterface instead.
+   *
+   * @see https://www.drupal.org/node/2926958
    */
   public function deleteRevision($revision_id);
 
diff --git a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
index b3fc12d..698ed85 100644
--- a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php
@@ -23,4 +23,18 @@ public function createTranslation(ContentEntityInterface $entity, $langcode, arr
    */
   public function createWithSampleValues($bundle = FALSE, array $values = []) {}
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getLatestRevisionId($entity_id) {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLatestAffectedRevisionId($entity_id, $langcode) {
+    return NULL;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/RevisionableInterface.php b/core/lib/Drupal/Core/Entity/RevisionableInterface.php
index 14690e3..e25bc25 100644
--- a/core/lib/Drupal/Core/Entity/RevisionableInterface.php
+++ b/core/lib/Drupal/Core/Entity/RevisionableInterface.php
@@ -52,6 +52,14 @@ public function getRevisionId();
   public function isDefaultRevision($new_value = NULL);
 
   /**
+   * Checks if this entity is the latest revision.
+   *
+   * @return bool
+   *   TRUE if the entity is the latest revision, FALSE otherwise.
+   */
+  public function isLatestRevision();
+
+  /**
    * Acts on a revision before it gets saved.
    *
    * @param EntityStorageInterface $storage
diff --git a/core/lib/Drupal/Core/Entity/RevisionableStorageInterface.php b/core/lib/Drupal/Core/Entity/RevisionableStorageInterface.php
new file mode 100644
index 0000000..6729c68
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/RevisionableStorageInterface.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Drupal\Core\Entity;
+
+/**
+ * A storage that supports revisionable entity types.
+ */
+interface RevisionableStorageInterface {
+
+  /**
+   * Loads a specific entity revision.
+   *
+   * @param int $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);
+
+  /**
+   * Deletes 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);
+
+  /**
+   * Returns the latest revision identifier for an entity.
+   *
+   * @param int|string $entity_id
+   *   The entity identifier.
+   *
+   * @return int|null
+   *   The latest revision identifier or NULL if no revision could be found.
+   */
+  public function getLatestRevisionId($entity_id);
+
+  /**
+   * Returns the latest affected revision identifier for an entity translation.
+   *
+   * @param int $entity_id
+   *   The entity identifier.
+   * @param string $langcode
+   *   The language code of the translation.
+   *
+   * @return int|null
+   *   The latest revision identifier or NULL if no revision could be found.
+   */
+  public function getLatestAffectedRevisionId($entity_id, $langcode);
+
+}
diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
index 1f6b42b..6e5957f 100644
--- a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
+++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
@@ -5,8 +5,6 @@
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\TypedData\TranslatableInterface;
 use Symfony\Component\Routing\Route;
 
@@ -71,8 +69,9 @@ public function convert($value, $definition, $name, array $defaults) {
     // If the entity type is revisionable and the parameter has the
     // "load_latest_revision" flag, load the latest revision.
     if ($entity instanceof ContentEntityInterface && !empty($definition['load_latest_revision']) && $entity_definition->isRevisionable()) {
-      $latest_revision_id = $this->getLatestRevisionId($storage, $entity_definition, $value);
-      if ($entity->getLoadedRevisionId() !== $latest_revision_id) {
+      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface  $storage */
+      $latest_revision_id = $storage->getLatestRevisionId($value);
+      if (!$entity->getLoadedRevisionId() !== $latest_revision_id) {
         $entity = $storage->loadRevision($latest_revision_id);
       }
     }
@@ -87,33 +86,6 @@ public function convert($value, $definition, $name, array $defaults) {
   }
 
   /**
-   * Get the latest revision ID.
-   *
-   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
-   *   The entity storage.
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_definition
-   *   The entity definition.
-   * @param mixed $value
-   *   The raw value.
-   *
-   * @return int
-   *   The latest revision ID for a given entity.
-   */
-  protected function getLatestRevisionId(EntityStorageInterface $storage, EntityTypeInterface $entity_definition, $value) {
-    // @todo, replace this query with a standardized way of getting the
-    //   latest revision in https://www.drupal.org/node/2784201.
-    $result = $storage
-      ->getQuery()
-      ->latestRevision()
-      ->condition($entity_definition->getKey('id'), $value)
-      // The entity converter is not concerned with access checking, skip the
-      // access check when looking up the latest revision.
-      ->accessCheck(FALSE)
-      ->execute();
-    return key($result);
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function applies($definition, $name, Route $route) {
diff --git a/core/modules/quickedit/quickedit.module b/core/modules/quickedit/quickedit.module
index 3d27050..999445b 100644
--- a/core/modules/quickedit/quickedit.module
+++ b/core/modules/quickedit/quickedit.module
@@ -11,7 +11,6 @@
  * entities, enabling them for in-place editing.
  */
 
-use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -130,10 +129,10 @@ function quickedit_preprocess_page_title(&$variables) {
 function quickedit_preprocess_field(&$variables) {
   $variables['#cache']['contexts'][] = 'user.permissions';
   $element = $variables['element'];
-  /** @var $entity \Drupal\Core\Entity\EntityInterface */
+  /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
   $entity = $element['#object'];
 
-  if (!\Drupal::currentUser()->hasPermission('access in-place editing') || !_quickedit_entity_is_latest_revision($entity)) {
+  if (!\Drupal::currentUser()->hasPermission('access in-place editing') || !$entity->isLatestRevision()) {
     return;
   }
 
@@ -157,41 +156,11 @@ function quickedit_preprocess_field(&$variables) {
  * Implements hook_entity_view_alter().
  */
 function quickedit_entity_view_alter(&$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
+  /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
   $build['#cache']['contexts'][] = 'user.permissions';
-  if (!\Drupal::currentUser()->hasPermission('access in-place editing') || !_quickedit_entity_is_latest_revision($entity)) {
+  if (!\Drupal::currentUser()->hasPermission('access in-place editing') || !$entity->isLatestRevision()) {
     return;
   }
 
   $build['#attributes']['data-quickedit-entity-id'] = $entity->getEntityTypeId() . '/' . $entity->id();
 }
-
-/**
- * Check if a loaded entity is the latest revision.
- *
- * @param \Drupal\Core\Entity\ContentEntityInterface $entity
- *   The entity to check.
- *
- * @return bool
- *   TRUE if the loaded entity is the latest revision, FALSE otherwise.
- *
- * @todo Remove this method once better support for pending revisions is added
- * to core https://www.drupal.org/node/2784201.
- *
- * @internal
- */
-function _quickedit_entity_is_latest_revision(ContentEntityInterface $entity) {
-  $entity_type_manager = \Drupal::entityTypeManager();
-  $entity_definition = $entity_type_manager->getDefinition($entity->getEntityTypeId());
-  if (!$entity_definition->isRevisionable()) {
-    return TRUE;
-  }
-  $revision_ids = $entity_type_manager
-    ->getStorage($entity->getEntityTypeId())
-    ->getQuery()
-    ->allRevisions()
-    ->condition($entity_definition->getKey('id'), $entity->id())
-    ->sort($entity_definition->getKey('revision'), 'DESC')
-    ->range(0, 1)
-    ->execute();
-  return $entity->getLoadedRevisionId() == array_keys($revision_ids)[0];
-}
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityLoadedRevisionTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionsTest.php
similarity index 86%
rename from core/tests/Drupal/KernelTests/Core/Entity/EntityLoadedRevisionTest.php
rename to core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionsTest.php
index a3b99fe..bd4b5b3 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityLoadedRevisionTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionsTest.php
@@ -8,9 +8,11 @@
 /**
  * Tests the loaded Revision of an entity.
  *
+ * @coversDefaultClass \Drupal\Core\Entity\ContentEntityBase
+ *
  * @group entity
  */
-class EntityLoadedRevisionTest extends EntityKernelTestBase {
+class EntityRevisionsTest extends EntityKernelTestBase {
 
   /**
    * Modules to enable.
@@ -164,7 +166,34 @@ public function testSaveInHookEntityInsert() {
     $loadedRevisionId = \Drupal::state()->get('entity_test.loadedRevisionId');
     $this->assertEquals($entity->getLoadedRevisionId(), $loadedRevisionId);
     $this->assertEquals($entity->getRevisionId(), $entity->getLoadedRevisionId());
+  }
+
+  /**
+   * @covers ::isLatestRevision
+   */
+  public function testIsLatestRevision() {
+    // Create a basic EntityTestMulRev entity and save it.
+    $entity = EntityTestMulRev::create();
+    $entity->save();
+
+    $this->assertTrue($entity->isLatestRevision());
+
+    // Load the created entity and create a new pending revision.
+    $pending_revision = EntityTestMulRev::load($entity->id());
+    $pending_revision->setNewRevision(TRUE);
+    $pending_revision->isDefaultRevision(FALSE);
+
+    // The pending revision should still be marked as the latest one before
+    // it is saved.
+    $this->assertTrue($pending_revision->isLatestRevision());
+
+    $pending_revision->save();
+    $this->assertTrue($pending_revision->isLatestRevision());
 
+    // Load the default revision and check that is not marked as the latest
+    // revision.
+    $default_revision = EntityTestMulRev::load($entity->id());
+    $this->assertFalse($default_revision->isLatestRevision());
   }
 
 }
