diff --git a/core/core.services.yml b/core/core.services.yml
index 5e2c9e3781..ed7fc61f66 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -965,7 +965,7 @@ services:
     class: Drupal\Core\ParamConverter\EntityConverter
     tags:
       - { name: paramconverter }
-    arguments: ['@entity.manager']
+    arguments: ['@entity.manager', '@language_manager']
   paramconverter.entity_revision:
     class: Drupal\Core\ParamConverter\EntityRevisionParamConverter
     tags:
@@ -976,7 +976,7 @@ services:
     tags:
       # Use a higher priority than EntityConverter, see the class for details.
       - { name: paramconverter, priority: 5 }
-    arguments: ['@entity.manager', '@config.factory', '@router.admin_context']
+    arguments: ['@entity.manager', '@config.factory', '@router.admin_context', '@language_manager']
     lazy: true
   route_subscriber.module:
     class: Drupal\Core\EventSubscriber\ModuleRouteSubscriber
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index b82af9bd31..ffdccc93b3 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -223,7 +223,7 @@ public function createRevision(RevisionableInterface $entity, $default = TRUE, $
     // translation and the other translations in the default revision. This
     // permits the creation of pending revisions that can always be saved as the
     // new default revision without reverting changes in other languages.
-    if (!$entity->isNew() && !$entity->isDefaultRevision() && $entity->isTranslatable() && $this->isAnyRevisionTranslated($entity)) {
+    if (!$entity->isNew() && !$entity->isDefaultRevision() && $entity->isTranslatable() && ($entity->getTranslationLanguages(FALSE) || $this->isAnyRevisionTranslated($entity))) {
       $active_langcode = $entity->language()->getId();
       $skipped_field_names = array_flip($this->getRevisionTranslationMergeSkippedFieldNames());
 
diff --git a/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php b/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php
index 438eaf8caa..c8cffa77b9 100644
--- a/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php
+++ b/core/lib/Drupal/Core/ParamConverter/AdminPathConfigEntityConverter.php
@@ -3,6 +3,7 @@
 namespace Drupal\Core\ParamConverter;
 
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Routing\AdminContext;
 use Symfony\Component\Routing\Route;
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -48,9 +49,11 @@ class AdminPathConfigEntityConverter extends EntityConverter {
    *   The config factory.
    * @param \Drupal\Core\Routing\AdminContext $admin_context
    *   The route admin context service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager, ConfigFactoryInterface $config_factory, AdminContext $admin_context) {
-    parent::__construct($entity_manager);
+  public function __construct(EntityManagerInterface $entity_manager, ConfigFactoryInterface $config_factory, AdminContext $admin_context, LanguageManagerInterface $language_manager) {
+    parent::__construct($entity_manager, $language_manager);
 
     $this->configFactory = $config_factory;
     $this->adminContext = $admin_context;
diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
index f76b327a86..63862d9fdc 100644
--- a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
+++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php
@@ -2,9 +2,14 @@
 
 namespace Drupal\Core\ParamConverter;
 
-use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\RevisionableInterface;
+use Drupal\Core\Entity\RevisionableStorageInterface;
+use Drupal\Core\Entity\TranslatableRevisionableStorageInterface;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\TypedData\TranslatableInterface;
 use Symfony\Component\Routing\Route;
 
@@ -46,14 +51,24 @@ class EntityConverter implements ParamConverterInterface {
    */
   protected $entityManager;
 
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
   /**
    * Constructs a new EntityConverter.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager) {
+  public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
     $this->entityManager = $entity_manager;
+    $this->languageManager = $language_manager;
   }
 
   /**
@@ -68,9 +83,10 @@ 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()) {
-      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface  $storage */
-      $latest_revision_id = $storage->getLatestRevisionId($value);
+    if ($entity instanceof RevisionableInterface && !empty($definition['load_latest_revision']) && $entity_definition->isRevisionable()) {
+      // Retrieve the latest revision ID taking translations into account.
+      /** @var \Drupal\Core\Entity\RevisionableStorageInterface $storage */
+      $latest_revision_id = $this->getLatestRevisionId($storage, $entity_definition, $value);
       // We explicitly perform a loose equality check, since a revision ID may
       // be returned as an integer or a string.
       if ($entity->getLoadedRevisionId() != $latest_revision_id) {
@@ -87,6 +103,53 @@ public function convert($value, $definition, $name, array $defaults) {
     return $entity;
   }
 
+  /**
+   * Returns the ID of the latest revision translation of the specified entity.
+   *
+   * When dealing with translatable entity types, this attempts to retrieve the
+   * latest revision ID affecting the translation matching the current content
+   * language. If none can be found, this falls back to the latest revision ID.
+   *
+   * @param \Drupal\Core\Entity\RevisionableStorageInterface $storage
+   *   The entity storage.
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type definition.
+   * @param int $entity_id
+   *   The entity ID.
+   *
+   * @return string
+   *   The latest revision ID for the specified entity.
+   */
+  protected function getLatestRevisionId(RevisionableStorageInterface $storage, EntityTypeInterface $entity_type, $entity_id) {
+    $latest_revision_id = NULL;
+
+    if ($storage instanceof TranslatableRevisionableStorageInterface && $entity_type->isTranslatable() && $this->languageManager->isMultilingual()) {
+      $langcode = $this->languageManager
+        ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)
+        ->getId();
+      $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity_id, $langcode);
+
+      // If the latest translation-affecting revision was a default revision, it
+      // is fine to load the latest revision instead. This will allow to handle
+      // all cases that do not work with pending revisions and always expect the
+      // latest revision being loaded (and being the default revision).
+      /** @var \Drupal\Core\Entity\TranslatableRevisionableInterface $revision */
+      $revision = $latest_revision_id ? $storage->loadRevision($latest_revision_id) : NULL;
+      if (!$revision || ($revision->wasDefaultRevision() && !$revision->isDefaultRevision())) {
+        $latest_revision_id = NULL;
+      }
+    }
+
+    // Fall back to the latest revisions if no affected revision for the current
+    // language could be found. This is acceptable as it means the entity is not
+    // translated. This is the correct logic also on monolingual sites.
+    if (!isset($latest_revision_id)) {
+      $latest_revision_id = $storage->getLatestRevisionId($entity_id);
+    }
+
+    return (string) $latest_revision_id;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/content_moderation/content_moderation.module b/core/modules/content_moderation/content_moderation.module
index 2ae1e0da3a..bc127dd2fd 100644
--- a/core/modules/content_moderation/content_moderation.module
+++ b/core/modules/content_moderation/content_moderation.module
@@ -118,6 +118,15 @@ function content_moderation_entity_translation_delete(EntityInterface $translati
     ->entityTranslationDelete($translation);
 }
 
+/**
+ * Implements hook_entity_prepare_form().
+ */
+function content_moderation_entity_prepare_form(EntityInterface $entity, $operation, FormStateInterface $form_state) {
+  \Drupal::service('class_resolver')
+    ->getInstanceFromDefinition(EntityTypeInfo::class)
+    ->entityPrepareForm($entity, $operation, $form_state);
+}
+
 /**
  * Implements hook_form_alter().
  */
@@ -243,6 +252,7 @@ function content_moderation_action_info_alter(&$definitions) {
  * Implements hook_entity_bundle_info_alter().
  */
 function content_moderation_entity_bundle_info_alter(&$bundles) {
+  $translatable = FALSE;
   /** @var \Drupal\workflows\WorkflowInterface $workflow */
   foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
     /** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration $plugin */
@@ -251,10 +261,16 @@ function content_moderation_entity_bundle_info_alter(&$bundles) {
       foreach ($plugin->getBundlesForEntityType($entity_type_id) as $bundle_id) {
         if (isset($bundles[$entity_type_id][$bundle_id])) {
           $bundles[$entity_type_id][$bundle_id]['workflow'] = $workflow->id();
+          // If we have even one translatable bundle for moderated entity types,
+          // we need to make the moderation state translatable as well.
+          if (!empty($bundles[$entity_type_id][$bundle_id]['translatable'])) {
+            $translatable = TRUE;
+          }
         }
       }
     }
   }
+  $bundles['content_moderation_state']['content_moderation_state']['translatable'] = $translatable;
 }
 
 /**
diff --git a/core/modules/content_moderation/src/Entity/ContentModerationState.php b/core/modules/content_moderation/src/Entity/ContentModerationState.php
index e54fbbe2a8..b56f0d8115 100644
--- a/core/modules/content_moderation/src/Entity/ContentModerationState.php
+++ b/core/modules/content_moderation/src/Entity/ContentModerationState.php
@@ -221,4 +221,16 @@ protected function realSave() {
     return parent::save();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getFieldsToSkipFromTranslationChangesCheck() {
+    $field_names = parent::getFieldsToSkipFromTranslationChangesCheck();
+    // We need to skip the parent entity revision ID, since that will always
+    // change on every save, otherwise every translation would be marked as
+    // affected regardless of actual changes.
+    $field_names[] = 'content_entity_revision_id';
+    return $field_names;
+  }
+
 }
diff --git a/core/modules/content_moderation/src/Entity/Handler/ModerationHandler.php b/core/modules/content_moderation/src/Entity/Handler/ModerationHandler.php
index f2c6917818..c44ab09841 100644
--- a/core/modules/content_moderation/src/Entity/Handler/ModerationHandler.php
+++ b/core/modules/content_moderation/src/Entity/Handler/ModerationHandler.php
@@ -35,11 +35,6 @@ public function onPresave(ContentEntityInterface $entity, $default_revision, $pu
     // This is probably not necessary if configuration is setup correctly.
     $entity->setNewRevision(TRUE);
     $entity->isDefaultRevision($default_revision);
-    if ($entity->hasField('revision_translation_affected')) {
-      // @todo remove this when revision and translation issues have been
-      // resolved. https://www.drupal.org/node/2860097
-      $entity->set('revision_translation_affected', TRUE);
-    }
 
     // Update publishing status if it can be updated and if it needs updating.
     if (($entity instanceof EntityPublishedInterface) && $entity->isPublished() !== $published_state) {
diff --git a/core/modules/content_moderation/src/Entity/Routing/EntityModerationRouteProvider.php b/core/modules/content_moderation/src/Entity/Routing/EntityModerationRouteProvider.php
index f72a47ede7..b7003eb1f8 100644
--- a/core/modules/content_moderation/src/Entity/Routing/EntityModerationRouteProvider.php
+++ b/core/modules/content_moderation/src/Entity/Routing/EntityModerationRouteProvider.php
@@ -88,7 +88,7 @@ protected function getLatestVersionRoute(EntityTypeInterface $entity_type) {
         ->setOption('parameters', [
           $entity_type_id => [
             'type' => 'entity:' . $entity_type_id,
-            'load_pending_revision' => 1,
+            'load_latest_revision' => 1,
           ],
         ]);
 
diff --git a/core/modules/content_moderation/src/EntityOperations.php b/core/modules/content_moderation/src/EntityOperations.php
index a7fcf7e8d9..6852aa3f69 100644
--- a/core/modules/content_moderation/src/EntityOperations.php
+++ b/core/modules/content_moderation/src/EntityOperations.php
@@ -101,7 +101,6 @@ public function entityPresave(EntityInterface $entity) {
       // This entity is default if it is new, a new translation, the default
       // revision, or the default revision is not published.
       $update_default_revision = $entity->isNew()
-        || $entity->isNewTranslation()
         || $current_state->isDefaultRevisionState()
         || !$this->moderationInfo->isDefaultRevisionPublished($entity);
 
@@ -147,9 +146,10 @@ protected function updateOrCreateFromEntity(EntityInterface $entity) {
     $entity_revision_id = $entity->getRevisionId();
     $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
     $content_moderation_state = ContentModerationStateEntity::loadFromModeratedEntity($entity);
+    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+    $storage = $this->entityTypeManager->getStorage('content_moderation_state');
 
     if (!($content_moderation_state instanceof ContentModerationStateInterface)) {
-      $storage = $this->entityTypeManager->getStorage('content_moderation_state');
       $content_moderation_state = $storage->create([
         'content_entity_type_id' => $entity->getEntityTypeId(),
         'content_entity_id' => $entity->id(),
@@ -159,11 +159,6 @@ protected function updateOrCreateFromEntity(EntityInterface $entity) {
       ]);
       $content_moderation_state->workflow->target_id = $workflow->id();
     }
-    elseif ($content_moderation_state->content_entity_revision_id->value != $entity_revision_id) {
-      // If a new revision of the content has been created, add a new content
-      // moderation state revision.
-      $content_moderation_state->setNewRevision(TRUE);
-    }
 
     // Sync translations.
     if ($entity->getEntityType()->hasKey('langcode')) {
@@ -176,6 +171,12 @@ protected function updateOrCreateFromEntity(EntityInterface $entity) {
       }
     }
 
+    // If a new revision of the content has been created, add a new content
+    // moderation state revision.
+    if (!$content_moderation_state->isNew() && $content_moderation_state->content_entity_revision_id->value !== $entity_revision_id) {
+      $content_moderation_state = $storage->createRevision($content_moderation_state, $entity->isDefaultRevision());
+    }
+
     // Create the ContentModerationState entity for the inserted entity.
     $moderation_state = $entity->moderation_state->value;
     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
@@ -245,23 +246,19 @@ public function entityTranslationDelete(EntityInterface $translation) {
    * @see EntityFieldManagerInterface::getExtraFields()
    */
   public function entityView(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
     if (!$this->moderationInfo->isModeratedEntity($entity)) {
       return;
     }
-    if (!$this->moderationInfo->isLatestRevision($entity)) {
-      return;
-    }
     if ($this->moderationInfo->isLiveRevision($entity)) {
       return;
     }
-    // Don't display the moderation form when when:
-    // - The revision is not translation affected.
-    // - There are more than one translation languages.
-    // - The entity has pending revisions.
-    if (!$this->moderationInfo->isPendingRevisionAllowed($entity)) {
+    // The moderation form should not be displayed when viewing old revisions.
+    // However it should be displayed if the latest affected revision is a
+    // pending revision.
+    if (!$entity->isDefaultRevision() && (($entity->wasDefaultRevision() && $this->moderationInfo->isDefaultRevisionPublished($entity)) || !$entity->isLatestTranslationAffectedRevision())) {
       return;
     }
-
     $component = $display->getComponent('content_moderation_control');
     if ($component) {
       $build['content_moderation_control'] = $this->formBuilder->getForm(EntityModerationForm::class, $entity);
diff --git a/core/modules/content_moderation/src/EntityTypeInfo.php b/core/modules/content_moderation/src/EntityTypeInfo.php
index 666ee2647f..74ea60af50 100644
--- a/core/modules/content_moderation/src/EntityTypeInfo.php
+++ b/core/modules/content_moderation/src/EntityTypeInfo.php
@@ -7,10 +7,12 @@
 use Drupal\Core\Entity\ContentEntityFormInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Form\FormInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
@@ -268,6 +270,37 @@ public function entityBaseFieldInfo(EntityTypeInterface $entity_type) {
     return $fields;
   }
 
+  /**
+   * Replaces the entity form entity object with a proper revision object.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity being edited.
+   * @param string $operation
+   *   The entity form operation.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   *
+   * @see hook_entity_prepare_form()
+   */
+  public function entityPrepareForm(EntityInterface $entity, $operation, FormStateInterface $form_state) {
+    /** @var \Drupal\Core\Entity\EntityFormInterface $form_object */
+    $form_object = $form_state->getFormObject();
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    if ($this->isModeratedEntityEditForm($form_object, $operation) && !$entity->isNew()) {
+      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+      $storage = $this->entityTypeManager->getStorage($entity->getEntityTypeId());
+      // Generate a proper revision object for the current entity. This allows
+      // to correctly handle translatable entities having pending revisions.
+      $new_revision = $storage->createRevision($entity, FALSE);
+      // Restore the revision ID as other modules may expect to find it still
+      // populated. The entity object wil be marked as a new revision on
+      // presave.
+      $revision_key = $new_revision->getEntityType()->getKey('revision');
+      $new_revision->set($revision_key, $new_revision->getLoadedRevisionId());
+      $form_object->setEntity($new_revision);
+    }
+  }
+
   /**
    * Alters bundle forms to enforce revision handling.
    *
@@ -291,57 +324,15 @@ public function formAlter(array &$form, FormStateInterface $form_state, $form_id
         $this->entityTypeManager->getHandler($config_entity_type->getBundleOf(), 'moderation')->enforceRevisionsBundleFormAlter($form, $form_state, $form_id);
       }
     }
-    elseif ($form_object instanceof ContentEntityFormInterface && in_array($form_object->getOperation(), ['edit', 'default'])) {
+    elseif ($this->isModeratedEntityEditForm($form_object)) {
+      /** @var \Drupal\Core\Entity\ContentEntityFormInterface $form_object */
+      /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
       $entity = $form_object->getEntity();
       if ($this->moderationInfo->isModeratedEntity($entity)) {
         $this->entityTypeManager
           ->getHandler($entity->getEntityTypeId(), 'moderation')
           ->enforceRevisionsEntityFormAlter($form, $form_state, $form_id);
 
-        if (!$this->moderationInfo->isPendingRevisionAllowed($entity)) {
-          $latest_revision = $this->moderationInfo->getLatestRevision($entity->getEntityTypeId(), $entity->id());
-          if ($entity->bundle()) {
-            $bundle_type_id = $entity->getEntityType()->getBundleEntityType();
-            $bundle = $this->entityTypeManager->getStorage($bundle_type_id)->load($entity->bundle());
-            $type_label = $bundle->label();
-          }
-          else {
-            $type_label = $entity->getEntityType()->getLabel();
-          }
-
-          $translation = $this->moderationInfo->getAffectedRevisionTranslation($latest_revision);
-          $args = [
-            '@type_label' => $type_label,
-            '@latest_revision_edit_url' => $translation->toUrl('edit-form', ['language' => $translation->language()])->toString(),
-            '@latest_revision_delete_url' => $translation->toUrl('delete-form', ['language' => $translation->language()])->toString(),
-          ];
-          $label = $this->t('Unable to save this @type_label.', $args);
-          $message = $this->t('<a href="@latest_revision_edit_url">Publish</a> or <a href="@latest_revision_delete_url">delete</a> the latest revision to allow all workflow transitions.', $args);
-          $full_message = $this->t('Unable to save this @type_label. <a href="@latest_revision_edit_url">Publish</a> or <a href="@latest_revision_delete_url">delete</a> the latest revision to allow all workflow transitions.', $args);
-          drupal_set_message($full_message, 'error');
-
-          $form['moderation_state']['#access'] = FALSE;
-          $form['actions']['#access'] = FALSE;
-          $form['invalid_transitions'] = [
-            'label' => [
-              '#type' => 'item',
-              '#prefix' => '<strong class="label">',
-              '#markup' => $label,
-              '#suffix' => '</strong>',
-            ],
-            'message' => [
-              '#type' => 'item',
-              '#markup' => $message,
-            ],
-            '#weight' => 999,
-            '#no_valid_transitions' => TRUE,
-          ];
-
-          if ($form['footer']) {
-            $form['invalid_transitions']['#group'] = 'footer';
-          }
-        }
-
         // Submit handler to redirect to the latest version, if available.
         $form['actions']['submit']['#submit'][] = [EntityTypeInfo::class, 'bundleFormRedirect'];
 
@@ -360,6 +351,23 @@ public function formAlter(array &$form, FormStateInterface $form_state, $form_id
     }
   }
 
+  /**
+   * Checks whether the specified form allows to edit a moderated entity.
+   *
+   * @param \Drupal\Core\Form\FormInterface $form_object
+   *   The form object.
+   * @param string|null $operation
+   *   The form operation.
+   *
+   * @return bool
+   *   TRUE if the form should get form moderation, FALSE otherwise.
+   */
+  protected function isModeratedEntityEditForm(FormInterface $form_object, $operation = NULL) {
+    return $form_object instanceof ContentEntityFormInterface &&
+      in_array($operation ?: $form_object->getOperation(), ['edit', 'default'], TRUE) &&
+      $this->moderationInfo->isModeratedEntity($form_object->getEntity());
+  }
+
   /**
    * Redirect content entity edit forms on save, if there is a pending revision.
    *
diff --git a/core/modules/content_moderation/src/Form/EntityModerationForm.php b/core/modules/content_moderation/src/Form/EntityModerationForm.php
index 507ef54485..98f6fdf2b9 100644
--- a/core/modules/content_moderation/src/Form/EntityModerationForm.php
+++ b/core/modules/content_moderation/src/Form/EntityModerationForm.php
@@ -138,6 +138,9 @@ public function buildForm(array $form, FormStateInterface $form_state, ContentEn
   public function submitForm(array &$form, FormStateInterface $form_state) {
     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
     $entity = $form_state->get('entity');
+    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+    $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
+    $entity = $storage->createRevision($entity, $entity->isDefaultRevision());
 
     $new_state = $form_state->getValue('new_state');
 
diff --git a/core/modules/content_moderation/src/ModerationInformation.php b/core/modules/content_moderation/src/ModerationInformation.php
index 7e3e513307..37b9156e6b 100644
--- a/core/modules/content_moderation/src/ModerationInformation.php
+++ b/core/modules/content_moderation/src/ModerationInformation.php
@@ -127,13 +127,6 @@ public function getAffectedRevisionTranslation(ContentEntityInterface $entity) {
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function isPendingRevisionAllowed(ContentEntityInterface $entity) {
-    return !(!$entity->isRevisionTranslationAffected() && count($entity->getTranslationLanguages()) > 1 && $this->hasPendingRevision($entity));
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -145,8 +138,19 @@ public function isLatestRevision(ContentEntityInterface $entity) {
    * {@inheritdoc}
    */
   public function hasPendingRevision(ContentEntityInterface $entity) {
-    return $this->isModeratedEntity($entity)
-      && !($this->getLatestRevisionId($entity->getEntityTypeId(), $entity->id()) == $this->getDefaultRevisionId($entity->getEntityTypeId(), $entity->id()));
+    $result = FALSE;
+    if ($this->isModeratedEntity($entity)) {
+      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+      $storage = $this->entityTypeManager->getStorage($entity->getEntityTypeId());
+      $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $entity->language()->getId());
+      $default_revision_id = $this->getDefaultRevisionId($entity->getEntityTypeId(), $entity->id());
+      if ($latest_revision_id !== $default_revision_id) {
+        /** @var \Drupal\Core\Entity\ContentEntityInterface $latest_revision */
+        $latest_revision = $storage->loadRevision($latest_revision_id);
+        $result = !$latest_revision->wasDefaultRevision();
+      }
+    }
+    return $result;
   }
 
   /**
@@ -154,8 +158,7 @@ public function hasPendingRevision(ContentEntityInterface $entity) {
    */
   public function isLiveRevision(ContentEntityInterface $entity) {
     $workflow = $this->getWorkflowForEntity($entity);
-    return $this->isLatestRevision($entity)
-      && $entity->isDefaultRevision()
+    return $entity->isDefaultRevision()
       && $entity->moderation_state->value
       && $workflow->getTypePlugin()->getState($entity->moderation_state->value)->isPublishedState();
   }
diff --git a/core/modules/content_moderation/src/ModerationInformationInterface.php b/core/modules/content_moderation/src/ModerationInformationInterface.php
index 1dafb3f71c..739c16b842 100644
--- a/core/modules/content_moderation/src/ModerationInformationInterface.php
+++ b/core/modules/content_moderation/src/ModerationInformationInterface.php
@@ -100,19 +100,6 @@ public function getDefaultRevisionId($entity_type_id, $entity_id);
    */
   public function getAffectedRevisionTranslation(ContentEntityInterface $entity);
 
-  /**
-   * Determines if pending revisions are allowed.
-   *
-   * @internal
-   *
-   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
-   *   The content entity.
-   *
-   * @return bool
-   *   If pending revisions are allowed.
-   */
-  public function isPendingRevisionAllowed(ContentEntityInterface $entity);
-
   /**
    * Determines if an entity is a latest revision.
    *
diff --git a/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php b/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php
index 8e7e3617a3..0e76f8e52b 100644
--- a/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php
+++ b/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php
@@ -2,11 +2,9 @@
 
 namespace Drupal\content_moderation\ParamConverter;
 
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\content_moderation\ModerationInformationInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\ParamConverter\EntityConverter;
-use Drupal\Core\TypedData\TranslatableInterface;
-use Drupal\content_moderation\ModerationInformationInterface;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -30,7 +28,7 @@ class EntityRevisionConverter extends EntityConverter {
    *   The moderation info utility service.
    */
   public function __construct(EntityManagerInterface $entity_manager, ModerationInformationInterface $moderation_info) {
-    parent::__construct($entity_manager);
+    parent::__construct($entity_manager, \Drupal::languageManager());
     $this->moderationInformation = $moderation_info;
   }
 
@@ -83,23 +81,8 @@ protected function isEditFormPage(Route $route) {
    * {@inheritdoc}
    */
   public function convert($value, $definition, $name, array $defaults) {
-    $entity = parent::convert($value, $definition, $name, $defaults);
-
-    if ($entity && $this->moderationInformation->isModeratedEntity($entity) && !$this->moderationInformation->isLatestRevision($entity)) {
-      $entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults);
-      $latest_revision = $this->moderationInformation->getLatestRevision($entity_type_id, $value);
-
-      if ($latest_revision instanceof EntityInterface) {
-        // If the entity type is translatable, ensure we return the proper
-        // translation object for the current context.
-        if ($entity instanceof TranslatableInterface) {
-          $latest_revision = $this->entityManager->getTranslationFromContext($latest_revision, NULL, ['operation' => 'entity_upcast']);
-        }
-        $entity = $latest_revision;
-      }
-    }
-
-    return $entity;
+    // @todo Deprecate this in https://www.drupal.org/node/2924812.
+    return parent::convert($value, $definition, $name, $defaults);
   }
 
 }
diff --git a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
index b5263639e2..6b4a9c2117 100644
--- a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
+++ b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
@@ -160,7 +160,6 @@ protected function updateModeratedEntity($moderation_state_id) {
       // This entity is default if it is new, a new translation, the default
       // revision state, or the default revision is not published.
       $update_default_revision = $entity->isNew()
-        || $entity->isNewTranslation()
         || $current_state->isDefaultRevisionState()
         || !$content_moderation_info->isDefaultRevisionPublished($entity);
 
diff --git a/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php b/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php
index 035ad3ea27..c658ef8759 100644
--- a/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php
+++ b/core/modules/content_moderation/src/Plugin/views/filter/ModerationStateFilter.php
@@ -176,8 +176,8 @@ protected function opSimple() {
         $entity_base_table_alias = $this->table;
 
         // The bundle field of an entity type is not revisionable so we need to
-        // join the data table.
-        $entity_base_table = $entity_type->isTranslatable() ? $entity_type->getDataTable() : $entity_type->getBaseTable();
+        // join the base table.
+        $entity_base_table = $entity_type->getBaseTable();
         $entity_revision_base_table = $entity_type->isTranslatable() ? $entity_type->getRevisionDataTable() : $entity_type->getRevisionTable();
         if ($this->table === $entity_revision_base_table) {
           $configuration = [
@@ -187,12 +187,6 @@ protected function opSimple() {
             'left_field' => $entity_type->getKey('id'),
             'type' => 'INNER',
           ];
-          if ($entity_type->isTranslatable()) {
-            $configuration['extra'][] = [
-              'field' => $entity_type->getKey('langcode'),
-              'left_field' => $entity_type->getKey('langcode'),
-            ];
-          }
 
           $join = Views::pluginManager('join')->createInstance('standard', $configuration);
           $entity_base_table_alias = $this->query->addRelationship($entity_base_table, $join, $entity_revision_base_table);
diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php
index 13fd0c0571..af4061b596 100644
--- a/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php
@@ -295,14 +295,6 @@ public function testContentTranslationNodeForm() {
     $this->drupalGet($latest_version_path, ['language' => $french]);
     $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
 
-    // It should not be possible to add a new english revision.
-    $this->drupalGet($edit_path);
-    $this->assertSession()->fieldNotExists('moderation_state[0][state]');
-    $this->assertSession()->pageTextContains('Unable to save this Moderated content.');
-
-    $this->clickLink('Publish');
-    $this->assertSession()->fieldValueEquals('body[0][value]', 'Third version of the content.');
-
     $this->drupalGet($edit_path);
     $this->clickLink('Delete');
     $this->assertSession()->buttonExists('Delete');
@@ -323,7 +315,7 @@ public function testContentTranslationNodeForm() {
     $this->drupalGet($latest_version_path, ['language' => $french]);
     $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
 
-    // Now we can publish the english (revision 5).
+    // Publish the English pending revision (revision 5).
     $this->drupalGet($edit_path);
     $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'published');
@@ -336,13 +328,13 @@ public function testContentTranslationNodeForm() {
     $this->drupalGet($latest_version_path);
     $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
 
-    // Make sure we're allowed to create a pending french revision.
+    // Make sure we are allowed to create a pending French revision.
     $this->drupalGet($edit_path, ['language' => $french]);
     $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'published');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
 
-    // Add a english pending revision (revision 6).
+    // Add an English pending revision (revision 6).
     $this->drupalGet($edit_path);
     $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'published');
@@ -354,16 +346,10 @@ public function testContentTranslationNodeForm() {
 
     $this->drupalGet($latest_version_path);
     $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]'));
-
-    // Make sure we're not allowed to create a pending french revision.
-    $this->drupalGet($edit_path, ['language' => $french]);
-    $this->assertSession()->fieldNotExists('moderation_state[0][state]');
-    $this->assertSession()->pageTextContains('Unable to save this Moderated content.');
-
     $this->drupalGet($latest_version_path, ['language' => $french]);
     $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
 
-    // We should be able to publish the english pending revision (revision 7)
+    // Publish the English pending revision (revision 7)
     $this->drupalGet($edit_path);
     $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'published');
@@ -376,44 +362,17 @@ public function testContentTranslationNodeForm() {
     $this->drupalGet($latest_version_path);
     $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]'));
 
-    // Make sure we're allowed to create a pending french revision.
+    // Make sure we are allowed to create a pending French revision.
     $this->drupalGet($edit_path, ['language' => $french]);
     $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'published');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
 
-    // Make sure we're allowed to create a pending english revision.
-    $this->drupalGet($edit_path);
-    $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
-    $this->assertSession()->optionExists('moderation_state[0][state]', 'published');
-    $this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
-
-    // Create new moderated content. (revision 1).
-    $this->drupalPostForm('node/add/moderated_content', [
-      'title[0][value]' => 'Second moderated content',
-      'body[0][value]' => 'First version of the content.',
-      'moderation_state[0][state]' => 'published',
-    ], t('Save'));
-
-    $node = $this->drupalGetNodeByTitle('Second moderated content');
-    $this->assertTrue($node->language(), 'en');
-    $edit_path = sprintf('node/%d/edit', $node->id());
-    $translate_path = sprintf('node/%d/translations/add/en/fr', $node->id());
-
-    // Add a pending revision (revision 2).
+    // Make sure we are allowed to create a pending English revision.
     $this->drupalGet($edit_path);
     $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'published');
     $this->assertSession()->optionExists('moderation_state[0][state]', 'archived');
-    $this->drupalPostForm(NULL, [
-      'body[0][value]' => 'Second version of the content.',
-      'moderation_state[0][state]' => 'draft',
-    ], t('Save'));
-
-    // It shouldn't be possible to translate as we have a pending revision.
-    $this->drupalGet($translate_path);
-    $this->assertSession()->fieldNotExists('moderation_state[0][state]');
-    $this->assertSession()->pageTextContains('Unable to save this Moderated content.');
 
     // Create new moderated content (revision 1).
     $this->drupalPostForm('node/add/moderated_content', [
@@ -444,11 +403,6 @@ public function testContentTranslationNodeForm() {
       'moderation_state[0][state]' => 'draft',
     ], t('Save (this translation)'));
 
-    // Editing the original translation should not be possible.
-    $this->drupalGet($edit_path);
-    $this->assertSession()->fieldNotExists('moderation_state[0][state]');
-    $this->assertSession()->pageTextContains('Unable to save this Moderated content.');
-
     // Updating and publishing the french translation is still possible.
     $this->drupalGet($edit_path, ['language' => $french]);
     $this->assertSession()->optionExists('moderation_state[0][state]', 'draft');
diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php
index 3104450fce..54013e9b2b 100644
--- a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\content_moderation\Functional;
 
+use Drupal\node\NodeInterface;
+
 /**
  * Test content_moderation functionality with localization and translation.
  *
@@ -22,19 +24,23 @@ class ModerationLocaleTest extends ModerationStateTestBase {
   ];
 
   /**
-   * Tests article translations can be moderated separately.
+   * {@inheritdoc}
    */
-  public function testTranslateModeratedContent() {
+  protected function setUp() {
+    parent::setUp();
+
     $this->drupalLogin($this->rootUser);
 
     // Enable moderation on Article node type.
     $this->createContentTypeFromUi('Article', 'article', TRUE);
 
-    // Add French language.
-    $edit = [
-      'predefined_langcode' => 'fr',
-    ];
-    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+    // Add French and Italian languages.
+    foreach (['fr', 'it'] as $langcode) {
+      $edit = [
+        'predefined_langcode' => $langcode,
+      ];
+      $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+    }
 
     // Enable content translation on articles.
     $this->drupalGet('admin/config/regional/content-language');
@@ -48,7 +54,12 @@ public function testTranslateModeratedContent() {
     // Adding languages requires a container rebuild in the test running
     // environment so that multilingual services are used.
     $this->rebuildContainer();
+  }
 
+  /**
+   * Tests article translations can be moderated separately.
+   */
+  public function testTranslateModeratedContent() {
     // Create a published article in English.
     $edit = [
       'title[0][value]' => 'Published English node',
@@ -191,4 +202,223 @@ public function testTranslateModeratedContent() {
     $this->assertFalse($french_node->isPublished());
   }
 
+  /**
+   * Tests that individual translations can be moderated independently.
+   */
+  public function testLanguageIndependentContentModeration() {
+    // Create a published article in English (revision 1).
+    $this->drupalGet('node/add/article');
+    $node = $this->submitNodeForm('Test 1.1 EN', 'published', 'en');
+    $this->assertNotLatestVersionPage($node);
+
+    $edit_path = sprintf('node/%d/edit', $node->id());
+    $translate_path = sprintf('node/%d/translations', $node->id());
+
+    // Create a new English draft (revision 2).
+    $this->drupalGet($edit_path);
+    $this->submitNodeForm('Test 1.2 EN', 'draft', 'en');
+    $this->assertLatestVersionPage($node);
+
+    // Add a French translation draft (revision 3).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Add'));
+    $this->submitNodeForm('Test 1.3 FR', 'draft');
+    $this->assertLatestVersionPage($node);
+
+    // Add an Italian translation draft (revision 4).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Add'));
+    $this->submitNodeForm('Test 1.4 IT', 'draft');
+    $this->assertLatestVersionPage($node);
+
+    // Publish the English draft (revision 5).
+    $this->drupalGet($edit_path);
+    $this->submitNodeForm('Test 1.5 EN', 'published', 'en');
+    $this->assertNotLatestVersionPage($node);
+
+    // Publish the Italian draft (revision 6).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 2);
+    $this->submitNodeForm('Test 1.6 IT', 'published');
+    $this->assertNotLatestVersionPage($node);
+
+    // Publish the French draft (revision 7).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 1);
+    $this->submitNodeForm('Test 1.7 FR', 'published');
+    $this->assertNotLatestVersionPage($node);
+
+    // Create an Italian draft (revision 8).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 2);
+    $this->submitNodeForm('Test 1.8 IT', 'draft');
+    $this->assertLatestVersionPage($node);
+
+    // Create a French draft (revision 9).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 1);
+    $this->submitNodeForm('Test 1.9 FR', 'draft');
+    $this->assertLatestVersionPage($node);
+
+    // Create an English draft (revision 10).
+    $this->drupalGet($edit_path);
+    $this->submitNodeForm('Test 1.10 EN', 'draft', 'en');
+    $this->assertLatestVersionPage($node);
+
+    // Now start from a draft article in English (revision 1).
+    $this->drupalGet('node/add/article');
+    $node = $this->submitNodeForm('Test 2.1 EN', 'draft', 'en');
+    $this->assertNotLatestVersionPage($node, TRUE);
+
+    $edit_path = sprintf('node/%d/edit', $node->id());
+    $translate_path = sprintf('node/%d/translations', $node->id());
+
+    // Add a French translation (revision 2).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Add'));
+    $this->submitNodeForm('Test 2.2 FR', 'draft');
+    $this->assertNotLatestVersionPage($node, TRUE);
+
+    // Add an Italian translation (revision 3).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Add'));
+    $this->submitNodeForm('Test 2.3 IT', 'draft');
+    $this->assertNotLatestVersionPage($node, TRUE);
+
+    // Publish the English draft (revision 4).
+    $this->drupalGet($edit_path);
+    $this->submitNodeForm('Test 2.4 EN', 'published', 'en');
+    $this->assertNotLatestVersionPage($node);
+
+    // Publish the Italian draft (revision 5).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 2);
+    $this->submitNodeForm('Test 2.5 IT', 'published');
+    $this->assertNotLatestVersionPage($node);
+
+    // Publish the French draft (revision 6).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 1);
+    $this->submitNodeForm('Test 2.6 FR', 'published');
+    $this->assertNotLatestVersionPage($node);
+
+    // Create an Italian draft (revision 7).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 2);
+    $this->submitNodeForm('Test 2.7 IT', 'draft');
+    $this->assertLatestVersionPage($node);
+
+    // Create a French draft (revision 8).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 1);
+    $this->submitNodeForm('Test 2.8 FR', 'draft');
+    $this->assertLatestVersionPage($node);
+
+    // Create an English draft (revision 9).
+    $this->drupalGet($edit_path);
+    $this->submitNodeForm('Test 2.9 EN', 'draft', 'en');
+    $this->assertLatestVersionPage($node);
+
+    // Now publish a draft in another language first and verify that the
+    // moderation form is not displayed on the English node view page.
+    $this->drupalGet('node/add/article');
+    $node = $this->submitNodeForm('Test 3.1 EN', 'published', 'en');
+    $this->assertNotLatestVersionPage($node);
+
+    $edit_path = sprintf('node/%d/edit', $node->id());
+    $translate_path = sprintf('node/%d/translations', $node->id());
+
+    // Create an English draft (revision 2).
+    $this->drupalGet($edit_path);
+    $this->submitNodeForm('Test 3.2 EN', 'draft', 'en');
+    $this->assertLatestVersionPage($node);
+
+    // Add a French translation (revision 3).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Add'));
+    $this->submitNodeForm('Test 3.3 FR', 'draft');
+    $this->assertLatestVersionPage($node);
+
+    // Publish the French draft (revision 4).
+    $this->drupalGet($translate_path);
+    $this->clickLink(t('Edit'), 1);
+    $this->submitNodeForm('Test 3.4 FR', 'published');
+    $this->assertNotLatestVersionPage($node);
+
+    // Check the English node view page.
+    $this->drupalGet($node->toUrl());
+    $this->assertNotLatestVersionPage($node);
+  }
+
+  /**
+   * Submits the node form at the current URL with the specified values.
+   *
+   * @param string $title
+   *   The node title.
+   * @param string $moderation_state
+   *   The moderation state.
+   * @param string|null $langcode
+   *   (optional) The node language. Defaults to none.
+   *
+   * @return \Drupal\node\NodeInterface|null
+   *   A node object if a new one is being created, NULL otherwise.
+   */
+  protected function submitNodeForm($title, $moderation_state, $langcode = NULL) {
+    $edit = [
+      'title[0][value]' => $title,
+      'moderation_state[0][state]' => $moderation_state,
+    ];
+    if (isset($langcode)) {
+      $edit['langcode[0][value]'] = $langcode;
+    }
+    $submit = $langcode === 'en' ? t('Save') : t('Save (this translation)');
+    $create = strpos($this->getSession()->getCurrentUrl(),  '/node/add/') !== FALSE;
+    $this->drupalPostForm(NULL, $edit, $submit);
+    $message = $create ? t('Article ' . $title . ' has been created.') : t('Article ' . $title . ' has been updated.');
+    $this->assertSession()->pageTextContains($message);
+    return $create ? $this->drupalGetNodeByTitle($title) : NULL;
+  }
+
+  /**
+   * Asserts that this is the "latest version" page for the specified node.
+   *
+   * @param \Drupal\node\NodeInterface $node
+   *   A node object.
+   */
+  public function assertLatestVersionPage(NodeInterface $node) {
+    $latest_version_path = sprintf('node/%d/latest', $node->id());
+    $this->assertNotSame(FALSE, strpos($this->getSession()->getCurrentUrl(), $latest_version_path));
+    $this->assertTrue($this->hasModerationForm());
+  }
+
+  /**
+   * Asserts that this is not the "latest version" page for the specified node.
+   *
+   * @param \Drupal\node\NodeInterface $node
+   *   A node object.
+   * @param bool $moderation_form
+   *   (optional) Whether the page should contain the moderation form. Defaults
+   *   to FALSE.
+   */
+  public function assertNotLatestVersionPage(NodeInterface $node, $moderation_form = FALSE) {
+    $latest_version_path = sprintf('node/%d/latest', $node->id());
+    $this->assertSame(FALSE, strpos($this->getSession()->getCurrentUrl(), $latest_version_path));
+    if ($moderation_form) {
+      $this->assertTrue($this->hasModerationForm());
+    }
+    else {
+      $this->assertFalse($this->hasModerationForm());
+    }
+  }
+
+  /**
+   * Checks whether the page contains the moderation form.
+   *
+   * @return bool
+   *   TRUE if the moderation form could be find in the page, FALSE otherwise.
+   */
+  public function hasModerationForm() {
+    return (bool) $this->xpath('//ul[@class="entity-moderation-form"]');
+  }
+
 }
diff --git a/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php b/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php
index a1b396fb45..00e107295a 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php
@@ -108,14 +108,12 @@ public function testContentModerationStateBaseJoin() {
     $expected_result = [
       [
         'nid' => $node->id(),
-        // @todo I would have expected that the content_moderation_state default
-        //   revision is the same one as in the node, but it isn't.
         // Joins from the base table to the default revision of the
         // content_moderation.
-        'moderation_state' => 'draft',
+        'moderation_state' => 'published',
         // Joins from the revision table to the default revision of the
         // content_moderation.
-        'moderation_state_1' => 'draft',
+        'moderation_state_1' => 'published',
         // Joins from the revision table to the revision of the
         // content_moderation.
         'moderation_state_2' => 'published',
diff --git a/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php b/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php
index 637e70a99f..da7ac9299d 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ViewsModerationStateFilterTest.php
@@ -121,10 +121,10 @@ public function testStateFilterViewsRelationship() {
     $translated_forward_revision->moderation_state = 'translated_draft';
     $translated_forward_revision->save();
 
-    // Four revisions for the nodes when no filter.
-    $this->assertNodesWithFilters([$node, $second_node, $third_node, $third_node], []);
+    // The three default revisions are listed when no filter is specified.
+    $this->assertNodesWithFilters([$node, $second_node, $third_node], []);
 
-    // The default revision of node one and three is published.
+    // The default revision of node one and three are published.
     $this->assertNodesWithFilters([$node, $third_node], [
       'default_revision_state' => 'editorial-published',
     ]);
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 48feccc6cd..9349824ca1 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -60,6 +60,13 @@ function content_translation_module_implements_alter(&$implementations, $hook) {
       unset($implementations['content_translation']);
       $implementations['content_translation'] = $group;
       break;
+
+    // Move our hook_entity_bundle_info_alter() implementation to the top of the
+    // list.
+    case 'entity_bundle_info_alter':
+      $group = $implementations['content_translation'];
+      $implementations = ['content_translation' => $group] + $implementations;
+      break;
   }
 }
 
@@ -422,16 +429,15 @@ function content_translation_form_field_config_edit_form_alter(array &$form, For
  */
 function content_translation_entity_presave(EntityInterface $entity) {
   if ($entity instanceof ContentEntityInterface && $entity->isTranslatable() && !$entity->isNew()) {
+    /** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */
+    $manager = \Drupal::service('content_translation.manager');
+    if (!$manager->isEnabled($entity->getEntityTypeId(), $entity->bundle())) {
+      return;
+    }
     // If we are creating a new translation we need to use the source language
     // as original language, since source values are the only ones available to
     // compare against.
-    if (!isset($entity->original)) {
-      $entity->original = \Drupal::entityTypeManager()
-        ->getStorage($entity->entityType())->loadUnchanged($entity->id());
-    }
     $langcode = $entity->language()->getId();
-    /** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */
-    $manager = \Drupal::service('content_translation.manager');
     $source_langcode = !$entity->original->hasTranslation($langcode) ? $manager->getTranslationMetadata($entity)->getSource() : NULL;
     \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $langcode, $source_langcode);
   }
diff --git a/core/modules/content_translation/src/Controller/ContentTranslationController.php b/core/modules/content_translation/src/Controller/ContentTranslationController.php
index 190778d42c..1fff1e8de7 100644
--- a/core/modules/content_translation/src/Controller/ContentTranslationController.php
+++ b/core/modules/content_translation/src/Controller/ContentTranslationController.php
@@ -87,6 +87,7 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
     $handler = $this->entityManager()->getHandler($entity_type_id, 'translation');
     $manager = $this->manager;
     $entity_type = $entity->getEntityType();
+    $revisionable = $entity_type->isRevisionable();
 
     // Start collecting the cacheability metadata, starting with the entity and
     // later merge in the access result cacheability metadata.
@@ -99,6 +100,9 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
 
     $rows = [];
     $show_source_column = FALSE;
+    $default_revision = $entity;
+    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+    $storage = $this->entityTypeManager()->getStorage($entity_type_id);
 
     if ($this->languageManager()->isMultilingual()) {
       // Determine whether the current entity is translatable.
@@ -121,6 +125,16 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
         $language_name = $language->getName();
         $langcode = $language->getId();
 
+        // If the entity type is revisionable, we may have pending revisions
+        // with translations not available yet in the default revision. Thus we
+        // need to load the latest translation-affecting revision for each
+        // language to be sure we are listing all available translations.
+        if ($revisionable) {
+          $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $langcode);
+          $entity = $latest_revision_id ? $storage->loadRevision($latest_revision_id) : $default_revision;
+          $translations = $entity->getTranslationLanguages();
+        }
+
         $add_url = new Url(
           "entity.$entity_type_id.content_translation_add",
           [
@@ -330,8 +344,21 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
    *   A processed form array ready to be rendered.
    */
   public function add(LanguageInterface $source, LanguageInterface $target, RouteMatchInterface $route_match, $entity_type_id = NULL) {
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
     $entity = $route_match->getParameter($entity_type_id);
 
+    // In case of a pending revision, make sure we load the latest
+    // translation-affecting revision for the source language, otherwise the
+    // form initial values may not be up to date.
+    if (!$entity->isDefaultRevision()) {
+      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+      $storage = $this->entityTypeManager()->getStorage($entity->getEntityTypeId());
+      $revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $source->getId());
+      if ($revision_id != $entity->getRevisionId()) {
+        $entity = $storage->loadRevision($revision_id);
+      }
+    }
+
     // @todo Exploit the upcoming hook_entity_prepare() when available.
     // See https://www.drupal.org/node/1810394.
     $this->prepareTranslation($entity, $source, $target);
diff --git a/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php b/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php
index 6aae426abe..d1107eb85f 100644
--- a/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php
+++ b/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php
@@ -70,6 +70,7 @@ protected function alterRoutes(RouteCollection $collection) {
           'parameters' => [
             $entity_type_id => [
               'type' => 'entity:' . $entity_type_id,
+              'load_latest_revision' => TRUE,
             ],
           ],
           '_admin_route' => $is_admin,
@@ -102,6 +103,7 @@ protected function alterRoutes(RouteCollection $collection) {
             ],
             $entity_type_id => [
               'type' => 'entity:' . $entity_type_id,
+              'load_latest_revision' => TRUE,
             ],
           ],
           '_admin_route' => $is_admin,
@@ -127,6 +129,7 @@ protected function alterRoutes(RouteCollection $collection) {
             ],
             $entity_type_id => [
               'type' => 'entity:' . $entity_type_id,
+              'load_latest_revision' => TRUE,
             ],
           ],
           '_admin_route' => $is_admin,
@@ -152,6 +155,7 @@ protected function alterRoutes(RouteCollection $collection) {
             ],
             $entity_type_id => [
               'type' => 'entity:' . $entity_type_id,
+              'load_latest_revision' => TRUE,
             ],
           ],
           '_admin_route' => $is_admin,
diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php
index 48401475fc..d91d3e1b05 100644
--- a/core/modules/node/src/Controller/NodeController.php
+++ b/core/modules/node/src/Controller/NodeController.php
@@ -173,6 +173,7 @@ public function revisionOverview(NodeInterface $node) {
 
     $rows = [];
     $default_revision = $node->getRevisionId();
+    $current_revision_displayed = FALSE;
 
     foreach ($this->getRevisionIds($node, $node_storage) as $vid) {
       /** @var \Drupal\node\NodeInterface $revision */
@@ -187,11 +188,17 @@ public function revisionOverview(NodeInterface $node) {
 
         // Use revision link to link to revisions that are not active.
         $date = $this->dateFormatter->format($revision->revision_timestamp->value, 'short');
-        if ($vid != $node->getRevisionId()) {
+
+        // We treat also the latest affected revision as current revision, if it
+        // was the default revision, as its values for the current language will
+        // be the same of the current default revision in this case.
+        $current_revision = $vid == $default_revision || (!$current_revision_displayed && $revision->wasDefaultRevision());
+        if (!$current_revision) {
           $link = $this->l($date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid]));
         }
         else {
           $link = $node->link($date);
+          $current_revision_displayed = TRUE;
         }
 
         $row = [];
@@ -210,7 +217,7 @@ public function revisionOverview(NodeInterface $node) {
         $this->renderer->addCacheableDependency($column['data'], $username);
         $row[] = $column;
 
-        if ($vid == $default_revision) {
+        if ($current_revision) {
           $row[] = [
             'data' => [
               '#prefix' => '<em>',
diff --git a/core/modules/node/src/Form/NodeRevisionRevertForm.php b/core/modules/node/src/Form/NodeRevisionRevertForm.php
index fc6fe023f5..e18ad77610 100644
--- a/core/modules/node/src/Form/NodeRevisionRevertForm.php
+++ b/core/modules/node/src/Form/NodeRevisionRevertForm.php
@@ -28,7 +28,7 @@ class NodeRevisionRevertForm extends ConfirmFormBase {
   /**
    * The node storage.
    *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
+   * @var \Drupal\node\NodeStorageInterface
    */
   protected $nodeStorage;
 
diff --git a/core/modules/node/src/Form/NodeRevisionRevertTranslationForm.php b/core/modules/node/src/Form/NodeRevisionRevertTranslationForm.php
index eb07b7af44..a6a4d85d8a 100644
--- a/core/modules/node/src/Form/NodeRevisionRevertTranslationForm.php
+++ b/core/modules/node/src/Form/NodeRevisionRevertTranslationForm.php
@@ -106,24 +106,9 @@ public function buildForm(array $form, FormStateInterface $form_state, $node_rev
    * {@inheritdoc}
    */
   protected function prepareRevertedRevision(NodeInterface $revision, FormStateInterface $form_state) {
-    $revert_untranslated_fields = $form_state->getValue('revert_untranslated_fields');
-
-    /** @var \Drupal\node\NodeInterface $default_revision */
-    $latest_revision = $this->nodeStorage->load($revision->id());
-    $latest_revision_translation = $latest_revision->getTranslation($this->langcode);
-
-    $revision_translation = $revision->getTranslation($this->langcode);
-
-    foreach ($latest_revision_translation->getFieldDefinitions() as $field_name => $definition) {
-      if ($definition->isTranslatable() || $revert_untranslated_fields) {
-        $latest_revision_translation->set($field_name, $revision_translation->get($field_name)->getValue());
-      }
-    }
-
-    $latest_revision_translation->setNewRevision();
-    $latest_revision_translation->isDefaultRevision(TRUE);
-
-    return $latest_revision_translation;
+    $revert_untranslated_fields = (bool) $form_state->getValue('revert_untranslated_fields');
+    $translation = $revision->getTranslation($this->langcode);
+    return $this->nodeStorage->createRevision($translation, TRUE, $revert_untranslated_fields);
   }
 
 }
diff --git a/core/modules/node/src/NodeViewBuilder.php b/core/modules/node/src/NodeViewBuilder.php
index 2bb7f4a2af..aec5d43089 100644
--- a/core/modules/node/src/NodeViewBuilder.php
+++ b/core/modules/node/src/NodeViewBuilder.php
@@ -89,7 +89,9 @@ public static function renderLinks($node_entity_id, $view_mode, $langcode, $is_i
     ];
 
     if (!$is_in_preview) {
-      $entity = Node::load($node_entity_id)->getTranslation($langcode);
+      /** @var \Drupal\node\NodeInterface $entity */
+      $entity = \Drupal::entityManager()
+        ->getTranslationFromContext(Node::load($node_entity_id), $langcode);
       $links['node'] = static::buildLinks($entity, $view_mode);
 
       // Allow other modules to alter the node links.
diff --git a/core/modules/node/src/Tests/NodeRevisionsTest.php b/core/modules/node/src/Tests/NodeRevisionsTest.php
index da5b260537..066193ddab 100644
--- a/core/modules/node/src/Tests/NodeRevisionsTest.php
+++ b/core/modules/node/src/Tests/NodeRevisionsTest.php
@@ -64,6 +64,9 @@ protected function setUp() {
     $field = FieldConfig::create($field_definition);
     $field->save();
 
+    // Enable translation for page nodes.
+    \Drupal::service('content_translation.manager')->setEnabled('node', 'page', TRUE);
+
     // Create and log in user.
     $web_user = $this->drupalCreateUser(
       [
diff --git a/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php b/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php
index a437e4aba8..3646ab3e01 100644
--- a/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php
+++ b/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php
@@ -160,10 +160,17 @@ public function testNodeRevisionsTabWithDefaultRevision() {
 
     $this->drupalGet('node/' . $node_id . '/revisions');
 
+    // Verify that the latest affected revision having been a default revision
+    // is displayed as the current one.
+    $this->assertNoLinkByHref('/node/' . $node_id . '/revisions/1/revert');
+    $elements = $this->xpath('//tr[contains(@class, "revision-current")]/td/a[1]');
+    // The site may be installed in a subdirectory, so check if the URL is
+    // contained in the retrieved one.
+    $this->assertContains('/node/1', current($elements)->getAttribute('href'));
+
     // Verify that the default revision can be an older revision than the latest
     // one.
-    // Assert that the revisions with translations changes are shown: 1 and 4.
-    $this->assertLinkByHref('/node/' . $node_id . '/revisions/1/revert');
+    // Assert that the revisions with translations changes are shown.
     $this->assertLinkByHref('/node/' . $node_id . '/revisions/4/revert');
 
     // Assert that the revisions without translations changes are filtered out:
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index a934ad65ac..ea6f7aa630 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -224,6 +224,7 @@ function entity_test_entity_bundle_info_alter(&$bundles) {
       }
     }
   }
+
 }
 
 /**
diff --git a/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php b/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php
index fb19d18a39..360ec1eeef 100644
--- a/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php
+++ b/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\ParamConverter\AdminPathConfigEntityConverter;
 use Drupal\Core\Routing\AdminContext;
 use Symfony\Component\Routing\Route;
@@ -43,8 +44,10 @@ class ViewUIConverter extends AdminPathConfigEntityConverter implements ParamCon
    *   The entity manager.
    * @param \Drupal\Core\TempStore\SharedTempStoreFactory $temp_store_factory
    *   The factory for the temp store object.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager, SharedTempStoreFactory $temp_store_factory, ConfigFactoryInterface $config_factory = NULL, AdminContext $admin_context = NULL) {
+  public function __construct(EntityManagerInterface $entity_manager, SharedTempStoreFactory $temp_store_factory, ConfigFactoryInterface $config_factory = NULL, AdminContext $admin_context = NULL, LanguageManagerInterface $language_manager = NULL) {
     // The config factory and admin context are new arguments due to changing
     // the parent. Avoid an error on updated sites by falling back to getting
     // them from the container.
@@ -55,7 +58,10 @@ public function __construct(EntityManagerInterface $entity_manager, SharedTempSt
     if (!$admin_context) {
       $admin_context = \Drupal::service('router.admin_context');
     }
-    parent::__construct($entity_manager, $config_factory, $admin_context);
+    if ($language_manager) {
+      $language_manager = \Drupal::languageManager();
+    }
+    parent::__construct($entity_manager, $config_factory, $admin_context, $language_manager);
 
     $this->tempStoreFactory = $temp_store_factory;
   }
diff --git a/core/modules/views_ui/views_ui.services.yml b/core/modules/views_ui/views_ui.services.yml
index adf87e61a2..da7a2ed457 100644
--- a/core/modules/views_ui/views_ui.services.yml
+++ b/core/modules/views_ui/views_ui.services.yml
@@ -1,7 +1,7 @@
 services:
   paramconverter.views_ui:
     class: Drupal\views_ui\ParamConverter\ViewUIConverter
-    arguments: ['@entity.manager', '@tempstore.shared', '@config.factory', '@router.admin_context']
+    arguments: ['@entity.manager', '@tempstore.shared', '@config.factory', '@router.admin_context', '@language_manager']
     tags:
       - { name: paramconverter, priority: 10 }
     lazy: true
diff --git a/core/tests/Drupal/KernelTests/Core/ParamConverter/EntityConverterLatestRevisionTest.php b/core/tests/Drupal/KernelTests/Core/ParamConverter/EntityConverterLatestRevisionTest.php
index d2fd2f5241..7933d9a4c1 100644
--- a/core/tests/Drupal/KernelTests/Core/ParamConverter/EntityConverterLatestRevisionTest.php
+++ b/core/tests/Drupal/KernelTests/Core/ParamConverter/EntityConverterLatestRevisionTest.php
@@ -80,8 +80,12 @@ public function testEntityWithPendingRevision() {
     $entity = EntityTestMulRev::create();
     $entity->save();
 
-    $entity->isDefaultRevision(FALSE);
-    $entity->setNewRevision(TRUE);
+    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+    $storage = $this->container->get('entity_type.manager')
+      ->getStorage($entity->getEntityTypeId());
+
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    $entity = $storage->createRevision($entity, FALSE);
     $entity->save();
 
     $converted = $this->converter->convert(1, [
diff --git a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php
index 54fcfbd73d..9d57aeef51 100644
--- a/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php
+++ b/core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php
@@ -22,6 +22,13 @@ class EntityConverterTest extends UnitTestCase {
    */
   protected $entityManager;
 
+  /**
+   * The mocked language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $languageManager;
+
   /**
    * The tested entity converter.
    *
@@ -36,8 +43,9 @@ protected function setUp() {
     parent::setUp();
 
     $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
+    $this->languageManager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface');
 
-    $this->entityConverter = new EntityConverter($this->entityManager);
+    $this->entityConverter = new EntityConverter($this->entityManager, $this->languageManager);
   }
 
   /**
