diff --git a/core/lib/Drupal/Core/Path/AliasStorage.php b/core/lib/Drupal/Core/Path/AliasStorage.php
index 4f380125bb..b856c9afa0 100644
--- a/core/lib/Drupal/Core/Path/AliasStorage.php
+++ b/core/lib/Drupal/Core/Path/AliasStorage.php
@@ -131,7 +131,12 @@ public function load($conditions) {
     foreach ($conditions as $field => $value) {
       if ($field == 'source' || $field == 'alias') {
         // Use LIKE for case-insensitive matching.
-        $select->condition($field, $this->connection->escapeLike($value), 'LIKE');
+        if (is_array($value)) {
+          $select->condition($field, $value, 'IN');
+        }
+        else {
+          $select->condition($field, $this->connection->escapeLike($value), 'LIKE');
+        }
       }
       else {
         $select->condition($field, $value);
@@ -160,7 +165,7 @@ public function delete($conditions) {
     foreach ($conditions as $field => $value) {
       if ($field == 'source' || $field == 'alias') {
         // Use LIKE for case-insensitive matching.
-        $query->condition($field, $this->connection->escapeLike($value), 'LIKE');
+        $query->condition($field, $value, 'LIKE');
       }
       else {
         $query->condition($field, $value);
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index 38cb57beee..03431c1b32 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Form\FormStateInterface;
@@ -86,8 +87,23 @@ function path_entity_translation_create(ContentEntityInterface $translation) {
     if ($field_definition->getType() === 'path' && $translation->get($field_name)->pid) {
       // If there are values and a path ID, update the langcode and unset the
       // path ID to save this as a new alias.
-      $translation->get($field_name)->langcode = $translation->language()->getId();
+      $translation->get($field_name)->langcode = $translation->language()
+        ->getId();
       $translation->get($field_name)->pid = NULL;
     }
   }
 }
+
+/**
+ * Implements hook_entity_revision_delete().
+ */
+function path_entity_revision_delete(EntityInterface $entity) {
+  $entity_type_id = $entity->getEntityTypeId();
+  $source = str_replace('{' . $entity_type_id . '}', $entity->id(), $entity->getEntityType()->getLinkTemplate('revision'));
+  $source = str_replace('{' . $entity_type_id . '_revision}', '%', $source);
+  $revisionable_conditions = [
+    'source' => $source,
+    'langcode' => $entity->language()->getId(),
+  ];
+  \Drupal::service('path.alias_storage')->delete($revisionable_conditions);
+}
diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
index a98e718696..a6e1144139 100644
--- a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
@@ -32,6 +32,15 @@ public function delete() {
       'langcode' => $entity->language()->getId(),
     ];
     \Drupal::service('path.alias_storage')->delete($conditions);
+
+    $entity_type_id = $entity->getEntityTypeId();
+    $source = str_replace('{' . $entity_type_id . '}', $entity->id(), $entity->getEntityType()->getLinkTemplate('revision'));
+    $source = str_replace('{' . $entity_type_id . '_revision}', '%', $source);
+    $revisionable_conditions = [
+      'source' => $source,
+      'langcode' => $entity->language()->getId(),
+    ];
+    \Drupal::service('path.alias_storage')->delete($revisionable_conditions);
   }
 
   /**
diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
index 53ddcc2689..75c82dbe8d 100644
--- a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
@@ -114,23 +114,33 @@ public function set($property_name, $value, $notify = TRUE) {
    * {@inheritdoc}
    */
   public function postSave($update) {
-    if (!$update) {
-      if ($this->alias) {
-        $entity = $this->getEntity();
-        if ($path = \Drupal::service('path.alias_storage')->save('/' . $entity->urlInfo()->getInternalPath(), $this->alias, $this->getLangcode())) {
-          $this->pid = $path['pid'];
-        }
+    /** @var \Drupal\Core\Path\AliasStorageInterface $alias_storage */
+    $alias_storage = \Drupal::service('path.alias_storage');
+
+    // Only process a non-empty alias.
+    $entity = $this->getEntity();
+    $canonical = '/' . $entity->toUrl()->getInternalPath();
+    if ($entity->getEntityType()->isRevisionable() && !$entity->isDefaultRevision()) {
+      $source = '/' . $entity->toUrl('revision')->getInternalPath();
+    }
+    else {
+      $source = $canonical;
+    }
+
+    if ($this->alias && (!$update || $source != $this->source)) {
+      $default_alias = $alias_storage->load(['source' => $canonical]);
+      if ($default_alias['alias'] != $this->alias && $path = $alias_storage->save($source, $this->alias, $this->getLangcode())) {
+        $this->pid = $path['pid'];
       }
     }
     else {
       // Delete old alias if user erased it.
-      if ($this->pid && !$this->alias) {
-        \Drupal::service('path.alias_storage')->delete(['pid' => $this->pid]);
+      if (!$this->alias) {
+        $alias_storage->delete(['source' => $source]);
       }
       // Only save a non-empty alias.
-      elseif ($this->alias) {
-        $entity = $this->getEntity();
-        \Drupal::service('path.alias_storage')->save('/' . $entity->urlInfo()->getInternalPath(), $this->alias, $this->getLangcode(), $this->pid);
+      elseif ($source) {
+        $alias_storage->save($source, $this->alias, $this->getLangcode(), $this->pid);
       }
     }
   }
@@ -164,12 +174,19 @@ protected function ensureLoaded() {
     if (!$this->isLoaded) {
       $entity = $this->getEntity();
       if (!$entity->isNew()) {
+        if ($entity->getEntityType()->isRevisionable() && !$entity->isDefaultRevision()) {
+          $conditions = ['source' => [
+            '/' . $entity->toUrl('revision')->getInternalPath(),
+            '/' . $entity->toUrl()->getInternalPath(),
+          ]];
+        }
+        else {
+          $conditions = ['source' => '/' . $entity->toUrl()->getInternalPath()];
+        }
+        $conditions['langcode'] = $this->getLangcode();
         // @todo Support loading languge neutral aliases in
         //   https://www.drupal.org/node/2511968.
-        $alias = \Drupal::service('path.alias_storage')->load([
-          'source' => '/' . $entity->toUrl()->getInternalPath(),
-          'langcode' => $this->getLangcode(),
-        ]);
+        $alias = \Drupal::service('path.alias_storage')->load($conditions);
         if ($alias) {
           $this->setValue($alias);
         }
diff --git a/core/modules/path/tests/src/Functional/PathContentModerationTest.php b/core/modules/path/tests/src/Functional/PathContentModerationTest.php
new file mode 100644
index 0000000000..32fef3d3f0
--- /dev/null
+++ b/core/modules/path/tests/src/Functional/PathContentModerationTest.php
@@ -0,0 +1,152 @@
+<?php
+
+namespace Drupal\Tests\path\Functional;
+
+use Drupal\Core\Path\AliasStorage;
+use Drupal\node\Entity\NodeType;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\workflows\Entity\Workflow;
+
+/**
+ * Tests path aliases with Content Moderation.
+ *
+ * @group path
+ */
+class PathContentModerationTest extends BrowserTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = ['node', 'path', 'content_moderation'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Created a content type.
+    $node_type = NodeType::create(['name' => 'moderated', 'type' => 'moderated']);
+    $node_type->save();
+
+    // Set the content type as moderated.
+    $workflow = Workflow::load('editorial');
+    $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated');
+    $workflow->save();
+
+    $this->drupalLogin($this->rootUser);
+  }
+
+  public function testNodePathAlias() {
+    // Create some moderated content with a path alias.
+    $this->drupalGet('node/add/moderated');
+    $this->assertSession()->fieldValueEquals('path[0][alias]', '');
+    $this->drupalPostForm(NULL, [
+      'title[0][value]' => 'moderated content',
+      'path[0][alias]' => '/moderated-content',
+    ], t('Save and Publish'));
+    $node = $this->getNodeByTitle('moderated content');
+
+    $this->drupalGet('/moderated-content');
+    $this->assertSession()->pageTextContains('moderated content');
+
+    // Add a forward revision with the same alias and check the alias is
+    // from the default revision.
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertSession()->fieldValueEquals('path[0][alias]', '/moderated-content');
+    $this->drupalPostForm(NULL, [
+      'title[0][value]' => 'forward revision',
+      'path[0][alias]' => '/moderated-content',
+    ], t('Save and Create New Draft'));
+
+    // Check the alias still shows the default content.
+    $this->drupalGet('/moderated-content');
+    $this->assertSession()->pageTextContains('moderated content');
+
+    // Add a third revision, updating alias, and check the alias still comes
+    // from the default.
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertSession()->fieldValueEquals('path[0][alias]', '/moderated-content');
+    $this->drupalPostForm(NULL, [
+      'title[0][value]' => 'revision three',
+      'path[0][alias]' => '/revision-three',
+    ], t('Save and Create New Draft'));
+
+    // Check both aliases return what we'd expect.
+    $this->drupalGet('/revision-three');
+    $this->assertSession()->pageTextContains('revision three');
+    $this->drupalGet('/moderated-content');
+    $this->assertSession()->pageTextContains('moderated content');
+
+    // Add another forward revision with no alias.
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertSession()->fieldValueEquals('path[0][alias]', '/revision-three');
+    $this->drupalPostForm('node/' . $node->id() . '/edit', [
+      'title[0][value]' => 'revision four',
+      'path[0][alias]' => '',
+    ], t('Save and Create New Draft'));
+
+    // The first two aliases should still work, and the revision with no alias
+    // should work on the revision path.
+    $this->drupalGet('/node/1/revisions/4/view');
+    $this->assertSession()->pageTextContains('revision four');
+    $this->drupalGet('/revision-three');
+    $this->assertSession()->pageTextContains('revision three');
+    $this->drupalGet('/moderated-content');
+    $this->assertSession()->pageTextContains('moderated content');
+
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertSession()->fieldValueEquals('path[0][alias]', '/moderated-content');
+    $this->drupalPostForm('node/' . $node->id() . '/edit', [
+      'title[0][value]' => 'revision five',
+      'path[0][alias]' => '/revision-five',
+    ], t('Save and Publish'));
+    $this->drupalGet('/revision-five');
+    $this->assertSession()->pageTextContains('revision five');
+    $this->drupalGet('/node/1/revisions/4/view');
+    $this->assertSession()->pageTextContains('revision four');
+    $this->drupalGet('/revision-three');
+    $this->assertSession()->pageTextContains('revision three');
+    $this->drupalGet('/moderated-content');
+    $this->assertSession()->statusCodeEquals('404');
+
+    $this->drupalPostForm('node/' . $node->id() . '/delete', [], t('Delete'));
+    $aliases = \Drupal::database()->select(AliasStorage::TABLE)->fields(AliasStorage::TABLE)->execute()->fetchAll();
+    $this->assertEquals([], $aliases);
+
+    // Create some moderated content with a path alias.
+    $this->drupalGet('node/add/moderated');
+    $this->assertSession()->fieldValueEquals('path[0][alias]', '');
+    $this->drupalPostForm(NULL, [
+      'title[0][value]' => 'moderated content 2',
+      'path[0][alias]' => '/moderated-content-2',
+    ], t('Save and Publish'));
+    $node = $this->getNodeByTitle('moderated content 2');
+
+    $this->drupalGet('/moderated-content-2');
+    $this->assertSession()->pageTextContains('moderated content 2');
+
+    // Add a forward revision with a new alias.
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertSession()->fieldValueEquals('path[0][alias]', '/moderated-content-2');
+    $this->drupalPostForm(NULL, [
+      'title[0][value]' => 'forward revision',
+      'path[0][alias]' => '/forward-revision',
+    ], t('Save and Create New Draft'));
+
+    // Check both aliases return what we'd expect.
+    $this->drupalGet('/forward-revision');
+    $this->assertSession()->pageTextContains('forward revision');
+    $this->drupalGet('/moderated-content-2');
+    $this->assertSession()->pageTextContains('moderated content 2');
+
+    // Delete the forward revision.
+    $this->drupalPostForm('node/2/revisions/7/delete', [], t('Delete'));
+    $this->drupalGet('/forward-revision');
+    $this->assertSession()->statusCodeEquals('404');
+    $this->drupalGet('/moderated-content-2');
+    $this->assertSession()->pageTextContains('moderated content 2');
+  }
+}
