diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
index 0836df17ab..679c98299e 100644
--- a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php
@@ -25,7 +25,7 @@ protected function computeValue() {
     $value = ['langcode' => $this->getLangcode()];
 
     $entity = $this->getEntity();
-    if (!$entity->isNew()) {
+    if (!$entity->isNew() && $entity->toUrl()->isRouted()) {
       /** @var \Drupal\path_alias\AliasRepositoryInterface $path_alias_repository */
       $path_alias_repository = \Drupal::service('path_alias.repository');
 
@@ -57,12 +57,14 @@ public function defaultAccess($operation = 'view', AccountInterface $account = N
   public function delete() {
     // Delete all aliases associated with this entity in the current language.
     $entity = $this->getEntity();
-    $path_alias_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
-    $entities = $path_alias_storage->loadByProperties([
-      'path' => '/' . $entity->toUrl()->getInternalPath(),
-      'langcode' => $entity->language()->getId(),
-    ]);
-    $path_alias_storage->delete($entities);
+    if ($entity->toUrl()->isRouted()) {
+      $path_alias_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
+      $entities = $path_alias_storage->loadByProperties([
+        'path' => '/' . $entity->toUrl()->getInternalPath(),
+        'langcode' => $entity->language()->getId(),
+      ]);
+      $path_alias_storage->delete($entities);
+    }
   }
 
 }
diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
index ba57f2467c..d1106a3caa 100644
--- a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
@@ -71,8 +71,9 @@ public function postSave($update) {
     // unspecified even if the field/entity has a specific langcode.
     $alias_langcode = ($this->langcode && $this->pid) ? $this->langcode : $this->getLangcode();
 
-    // If we have an alias, we need to create or update a path alias entity.
-    if ($this->alias) {
+    // If we have an alias and the entity has an internal path,
+    // we need to create or update a path alias entity.
+    if ($this->alias && $entity->toUrl()->isRouted()) {
       if (!$update || !$this->pid) {
         $path_alias = $path_alias_storage->create([
           'path' => '/' . $entity->toUrl()->getInternalPath(),
@@ -91,8 +92,9 @@ public function postSave($update) {
         }
       }
     }
-    elseif ($this->pid && !$this->alias) {
-      // Otherwise, delete the old alias if the user erased it.
+    elseif ($this->pid && (!$this->alias || !$entity->toUrl()->isRouted())) {
+      // Otherwise, delete the old alias if the user erased it or the entity's
+      // url has become unrouted.
       $path_alias = $path_alias_storage->load($this->pid);
       if ($entity->isDefaultRevision()) {
         $path_alias_storage->delete([$path_alias]);
diff --git a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
index 088ef784e2..75547321cc 100644
--- a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
+++ b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
@@ -43,7 +43,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     ];
     $element['source'] = [
       '#type' => 'value',
-      '#value' => !$entity->isNew() ? '/' . $entity->toUrl()->getInternalPath() : NULL,
+      '#value' => !$entity->isNew() && $entity->toUrl()->isRouted() ? '/' . $entity->toUrl()->getInternalPath() : NULL,
     ];
     $element['langcode'] = [
       '#type' => 'value',
@@ -87,6 +87,11 @@ public static function validateFormElement(array &$element, FormStateInterface $
     if ($alias !== '') {
       $form_state->setValueForElement($element['alias'], $alias);
 
+      $entity = $form_state->getFormObject()->getEntity();
+      if (!$entity->isNew() && !$entity->toUrl()->isRouted()) {
+        $form_state->setError($element['alias'], t('An unrouted entity cannot have a path.'));
+      }
+
       /** @var \Drupal\path_alias\PathAliasInterface $path_alias */
       $path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([
         'path' => $element['source']['#value'],
diff --git a/core/modules/path/tests/modules/path_entity_test_external/path_entity_test_external.info.yml b/core/modules/path/tests/modules/path_entity_test_external/path_entity_test_external.info.yml
new file mode 100644
index 0000000000..7e5a5d23ba
--- /dev/null
+++ b/core/modules/path/tests/modules/path_entity_test_external/path_entity_test_external.info.yml
@@ -0,0 +1,5 @@
+name: 'Path entity_test_external'
+type: module
+description: 'Supports test with entity_test_external entity type.'
+package: Testing
+version: VERSION
diff --git a/core/modules/path/tests/modules/path_entity_test_external/path_entity_test_external.module b/core/modules/path/tests/modules/path_entity_test_external/path_entity_test_external.module
new file mode 100644
index 0000000000..a9fcb24c62
--- /dev/null
+++ b/core/modules/path/tests/modules/path_entity_test_external/path_entity_test_external.module
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Hooks for path_entity_test_external module.
+ */
+
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+
+/**
+ * Implements hook_entity_base_field_info().
+ */
+function path_entity_test_external_entity_base_field_info(EntityTypeInterface $entity_type) {
+  if ($entity_type->id() === 'entity_test_external') {
+    $fields['path'] = BaseFieldDefinition::create('path')
+      ->setLabel(t('URL alias'))
+      ->setTranslatable(TRUE)
+      ->setDisplayOptions('form', [
+        'type' => 'path',
+        'weight' => 30,
+      ])
+      ->setDisplayConfigurable('form', TRUE)
+      ->setComputed(TRUE);
+
+    return $fields;
+  }
+}
diff --git a/core/modules/path/tests/src/Functional/PathEntityTestExternalFormTest.php b/core/modules/path/tests/src/Functional/PathEntityTestExternalFormTest.php
new file mode 100644
index 0000000000..2e04f22290
--- /dev/null
+++ b/core/modules/path/tests/src/Functional/PathEntityTestExternalFormTest.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\Tests\path\Functional;
+
+use Drupal\entity_test\Entity\EntityTestExternal;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the Path form UI for external entity.
+ *
+ * @group path
+ */
+class PathEntityTestExternalFormTest extends BrowserTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  protected static $modules = [
+    'entity_test',
+    'path',
+    'path_entity_test_external',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * Tests the Path form UI.
+   */
+  public function testEntityTestExternalForm() {
+    $this->drupalLogin($this->drupalCreateUser([
+      'administer entity_test content',
+      'create url aliases',
+    ]));
+
+    // Create an entity_test_external entity.
+    $this->drupalGet('/entity_test_external/add');
+    $this->submitForm([], 'Save');
+    $this->assertSession()->statusMessageContains('entity_test_external 1 has been created.', 'status');
+    // Update the entity.
+    $this->drupalGet('/entity_test_external/1/edit');
+    $this->submitForm([], 'Save');
+    $this->assertSession()->statusMessageContains('entity_test_external 1 has been updated.', 'status');
+    // Try to set a path.
+    $this->drupalGet('/entity_test_external/1/edit');
+    $this->submitForm(['path[0][alias]' => '/something'], 'Save');
+    $this->assertSession()->statusMessageContains('An unrouted entity cannot have a path.', 'error');
+    // Delete the entity.
+    $entity = EntityTestExternal::load('1');
+    $entity->delete();
+  }
+
+}
diff --git a/core/modules/path/tests/src/Unit/Field/PathFieldItemListTest.php b/core/modules/path/tests/src/Unit/Field/PathFieldItemListTest.php
new file mode 100644
index 0000000000..f6173ba84c
--- /dev/null
+++ b/core/modules/path/tests/src/Unit/Field/PathFieldItemListTest.php
@@ -0,0 +1,130 @@
+<?php
+
+namespace Drupal\Tests\path\Unit\Field;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\path\Plugin\Field\FieldType\PathFieldItemList;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\path\Plugin\Field\FieldType\PathFieldItemList
+ * @group path
+ */
+class PathFieldItemListTest extends UnitTestCase {
+
+  /**
+   * @covers ::getValue
+   *
+   * @param bool $is_routed
+   *   Whether the parent entity has internal path.
+   * @param bool $is_new
+   *   Whether the parent entity is new.
+   * @param array|null $expected_path_alias
+   *   Expected array returned by path_alias.repository services.
+   *
+   * @dataProvider providerTestComputeValue
+   */
+  public function testComputeValue(bool $is_routed, bool $is_new, $expected_path_alias): void {
+
+    // Our expected value is the expected path alias with minor changes.
+    if ($expected_path_alias) {
+      $expected = [
+        'alias' => $expected_path_alias['alias'],
+        'pid' => $expected_path_alias['id'],
+        'langcode' => $expected_path_alias['langcode'],
+      ];
+    }
+    else {
+      $expected['langcode'] = 'und';
+    }
+
+    $created_value = $this->createMock('Drupal\Core\TypedData\TypedDataInterface');
+    $created_value->expects($this->any())
+      ->method('getValue')
+      ->willReturn($expected);
+
+    $url = $this->createMock('Drupal\Core\Url');
+    $url->expects($this->any())
+      ->method('isRouted')
+      ->willReturn($is_routed);
+    if ($is_routed) {
+      $url->expects($this->any())
+        ->method('getInternalPath')
+        ->willReturn('some_internal_path');
+    }
+    else {
+      $url->expects($this->any())
+        ->method('getInternalPath')
+        ->willThrowException(new \UnexpectedValueException());
+    }
+
+    $parent_entity = $this->createMock('Drupal\Core\Entity\EntityInterface');
+    $parent_entity->expects($this->once())
+      ->method('isNew')
+      ->willReturn($is_new);
+    $parent_entity->expects($this->any())
+      ->method('toUrl')
+      ->willReturn($url);
+
+    $parent_typed_data = $this->createMock('Drupal\Core\TypedData\TypedDataInterface');
+    $parent_typed_data->expects($this->once())
+      ->method('getValue')
+      ->willReturn($parent_entity);
+
+    $field_definition = $this->createMock('Drupal\Core\Field\FieldDefinitionInterface');
+
+    $path_field_list = new PathFieldItemList($field_definition, NULL, $parent_typed_data);
+
+    // Dependency injection is not used twice within the scope of the covered
+    // code. First, \Drupal::service('path_alias.repository') is called
+    // in PathFieldItemList::computeValue() (which itself is called from
+    // PathFieldItemList::getValue()). Second,
+    // \Drupal::service('plugin.manager.field.field_type') is called from
+    // PathFieldItemList::createItem() (which itself is called from
+    // PathFieldItemList::computeValue()). Therefore, we must mock the field
+    // type manager and path alias repository and set them on the container.
+    $field_type_manager = $this->createMock('Drupal\Core\Field\FieldTypePluginManagerInterface');
+    $field_type_manager->expects($this->any())
+      ->method('createFieldItem')
+      ->with($path_field_list, 0, $expected)
+      ->willReturn($created_value);
+    $path_alias_repository = $this->createMock('Drupal\path_alias\AliasRepositoryInterface');
+    $path_alias_repository->expects($this->any())
+      ->method('lookupBySystemPath')
+      ->willReturn($expected_path_alias);
+    $container = new ContainerBuilder();
+    $container->set('path_alias.repository', $path_alias_repository);
+    $container->set('plugin.manager.field.field_type', $field_type_manager);
+    \Drupal::setContainer($container);
+
+    $this->assertSame($expected, $path_field_list->getValue()[0]);
+  }
+
+  /**
+   * Data provider for testComputeValue.
+   */
+  public function providerTestComputeValue(): array {
+    return [
+      'new entity' => [
+        'is_routed' => FALSE,
+        'is_new' => TRUE,
+        'expected_path_alias' => NULL,
+      ],
+      'entity with internal path' => [
+        'is_routed' => TRUE,
+        'is_new' => FALSE,
+        'expected_path_alias' => [
+          'alias' => 'some_alias',
+          'id' => 123,
+          'langcode' => 'und',
+        ],
+      ],
+      'entity without internal path' => [
+        'is_routed' => FALSE,
+        'is_new' => FALSE,
+        'expected_path_alias' => NULL,
+      ],
+    ];
+  }
+
+}
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php
index b6587a9a9e..c2a80bdeb2 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php
@@ -10,14 +10,26 @@
  * @ContentEntityType(
  *   id = "entity_test_external",
  *   label = @Translation("Entity test external"),
+ *   handlers = {
+ *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
+ *     "form" = {
+ *       "default" = "Drupal\entity_test\EntityTestForm",
+ *     },
+ *     "route_provider" = {
+ *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
+ *     },
+ *   },
  *   base_table = "entity_test_external",
  *   entity_keys = {
  *     "id" = "id",
  *     "uuid" = "uuid",
  *     "bundle" = "type",
+ *     "label" = "name",
  *   },
  *   links = {
- *     "canonical" = "/entity_test_external/{entity_test_external}"
+ *     "canonical" = "/entity_test_external/{entity_test_external}",
+ *     "add-form" = "/entity_test_external/add",
+ *     "edit-form" = "/entity_test_external/{entity_test_external}/edit",
  *   },
  * )
  */
diff --git a/core/phpstan-baseline.neon b/core/phpstan-baseline.neon
index b4aabda84a..a073f950db 100644
--- a/core/phpstan-baseline.neon
+++ b/core/phpstan-baseline.neon
@@ -1737,7 +1737,7 @@ parameters:
 
 		-
 			message: "#^Access to an undefined property Drupal\\\\path\\\\Plugin\\\\Field\\\\FieldType\\\\PathItem\\:\\:\\$alias\\.$#"
-			count: 3
+			count: 4
 			path: modules/path/src/Plugin/Field/FieldType/PathItem.php
 
 		-
