diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index 6a8c17a46e79a77e5060ea06956d435d610c5c8a..8c59abe4d8b56bd6728a5de68f00c209dd2923c8 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -353,6 +353,9 @@ protected static function fromEntityUri(array $uri_parts, array $options, $uri)
    *
    * @return \Drupal\Core\Url
    *   A new Url object for a 'user-path:' URI.
+   *
+   * @throws \InvalidArgumentException
+   *   Thrown when the URI's path component doesn't have a leading slash.
    */
   protected static function fromUserPathUri(array $uri_parts, array $options) {
     // Both PathValidator::getUrlIfValidWithoutAccessCheck() and 'base:' URIs
@@ -366,6 +369,9 @@ protected static function fromUserPathUri(array $uri_parts, array $options) {
       $uri_parts['path'] = '<front>';
     }
     else {
+      if ($uri_parts['path'][0] !== '/') {
+        throw new \InvalidArgumentException(String::format('The user-path path component "@path" is invalid. Its path component must have a leading slash, e.g. user-path:/foo.', ['@path' => $uri_parts['path']]));
+      }
       // Remove the leading slash.
       $uri_parts['path'] = substr($uri_parts['path'], 1);
     }
diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index 3203423b5edf19451356217a3dee58f94dfe62e6..e90d41686cdd1b5eb6246171035a8c4dfe79b5a7 100644
--- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -154,6 +154,7 @@ public static function validateUriElement($element, FormStateInterface $form_sta
     //   https://www.drupal.org/node/2421941
     if (parse_url($uri, PHP_URL_SCHEME) === 'user-path' && !in_array($element['#value'][0], ['/', '?', '#'], TRUE) && substr($element['#value'], 0, 7) !== '<front>') {
       $form_state->setError($element, t('Manually entered paths should start with /, ? or #.'));
+      return;
     }
 
     // If the URI is empty or not well-formed, the link field type's validation
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index 4096e3d2658a242059dd6fb54da2fd4412564456..d57ae8b3365545f06464dde032b956eda7b3d56e 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -636,6 +636,78 @@ public function providerTestToUriStringForUserPath() {
     ];
   }
 
+  /**
+   * Tests the fromUri() method with a valid user-path: URI.
+   *
+   * @covers ::fromUri
+   * @dataProvider providerFromValidUserPathUri
+   */
+  public function testFromValidUserPathUri($path) {
+    $url = Url::fromUri('user-path:' . $path);
+    $this->assertInstanceOf('Drupal\Core\Url', $url);
+  }
+
+  /**
+   * Data provider for testFromValidUserPathUri().
+   */
+  public function providerFromValidUserPathUri() {
+    return [
+      // Normal paths with a leading slash.
+      ['/kittens'],
+      ['/kittens/bengal'],
+      // Fragments with and without leading slashes.
+      ['/#about-our-kittens'],
+      ['/kittens#feeding'],
+      ['#feeding'],
+      // Query strings with and without leading slashes.
+      ['/kittens?page=1000'],
+      ['/?page=1000'],
+      ['?page=1000'],
+      // Paths with various token formats but no leading slash.
+      ['/[duckies]'],
+      ['/%bunnies'],
+      ['/{{ puppies }}'],
+      // Disallowed characters in the authority (host name) that are valid
+      // elsewhere in the path.
+      ['/(:;2&+h^'],
+      ['/AKI@&hO@'],
+    ];
+  }
+
+  /**
+   * Tests the fromUri() method with an invalid user-path: URI.
+   *
+   * @covers ::fromUri
+   * @expectedException \InvalidArgumentException
+   * @dataProvider providerFromInvalidUserPathUri
+   */
+  public function testFromInvalidUserPathUri($path) {
+    Url::fromUri('user-path:' . $path);
+  }
+
+  /**
+   * Data provider for testFromInvalidUserPathUri().
+   */
+  public function providerFromInvalidUserPathUri() {
+    return [
+      // Normal paths without a leading slash.
+      ['kittens'],
+      ['kittens/bengal'],
+      // Path without a leading slash containing a fragment.
+      ['kittens#feeding'],
+      // Path without a leading slash containing a query string.
+      ['kittens?page=1000'],
+      // Paths with various token formats but no leading slash.
+      ['[duckies]'],
+      ['%bunnies'],
+      ['{{ puppies }}'],
+      // Disallowed characters in the authority (host name) that are valid
+      // elsewhere in the path.
+      ['(:;2&+h^'],
+      ['AKI@&hO@'],
+    ];
+  }
+
   /**
    * Tests the toUriString() method with route: URIs.
    *