diff --git a/core/lib/Drupal/Core/Form/ConfirmFormHelper.php b/core/lib/Drupal/Core/Form/ConfirmFormHelper.php
index 8d608f1..d7b557e 100644
--- a/core/lib/Drupal/Core/Form/ConfirmFormHelper.php
+++ b/core/lib/Drupal/Core/Form/ConfirmFormHelper.php
@@ -34,7 +34,8 @@ public static function buildCancelLink(ConfirmFormInterface $form, Request $requ
     // If a destination is specified, that serves as the cancel link.
     if ($query->has('destination')) {
       $options = UrlHelper::parse($query->get('destination'));
-      $url = Url::fromUri('user-path:/' . $options['path'], $options);
+      // @todo Revist this in https://www.drupal.org/node/2418219.
+      $url = Url::fromUserInput('/' . $options['path'], $options);
     }
     // Check for a route-based cancel link.
     else {
diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index 8c59abe..604f960 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -166,7 +166,8 @@ public function __construct($route_name, $route_parameters = array(), $options =
    * @return \Drupal\Core\Url
    *   A new Url object for a routed (internal to Drupal) URL.
    *
-   * @see static::fromUri()
+   * @see \Drupal\Core\Url::fromUserInput()
+   * @see \Drupal\Core\Url::fromUri()
    */
   public static function fromRoute($route_name, $route_parameters = array(), $options = array()) {
     return new static($route_name, $route_parameters, $options);
@@ -190,6 +191,45 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
   }
 
   /**
+   * Creates a Url object for a relative URI reference submitted by user input.
+   *
+   * Use this method to create a URL for user-entered paths that may or may not
+   * correspond to a valid Drupal route.
+   *
+   * @param string $user_input
+   *   User input for a link or path. The first character must be one of the
+   *   following characters:
+   *   - '/': A base-relative path for the current site.
+   *   - '?': A query string for the current page or resource.
+   *   - '#': A fragment (jump-link) on the current page or resource.
+   *   This helps reduce ambiguity for user-entered links and paths, and
+   *   supports user interfaces where users may normally use auto-completion
+   *   to search for existing resources, but also may type one of these
+   *   characters to link to (e.g.) a specific path on the site.
+   *   (With regard to the URI specification, the user input is treated as a
+   *   @link https://tools.ietf.org/html/rfc3986#section-4.2 relative URI reference @endlink
+   *   where the relative part is of type
+   *   @link https://tools.ietf.org/html/rfc3986#section-3.3 path-abempty @endlink.)
+   * @param array $options
+   *   (optional) An array of options. See Url::fromUri() for details.
+   *
+   * @return static
+   *   A new Url object based on user input.
+   *
+   * @throws \InvalidArgumentException
+   *   Thrown when the user input does not begin with one of the following
+   *   characters: '/', '?', or '#'.
+   */
+  public static function fromUserInput($user_input, $options = []) {
+    if ((strpos($user_input, '/') !== 0) && (strpos($user_input, '#') !== 0) && (strpos($user_input, '?') !== 0)) {
+      throw new \InvalidArgumentException(String::format("The user-entered string @user_input must begin with a '/', '?', or '#'.", ['@user_input' => $user_input]));
+    }
+    // Appending the scheme below ensures that the user input is treated as a
+    // relative (not absolute) reference.
+    return static::fromUri('internal:' . $user_input, $options);
+  }
+
+  /**
    * Creates a new Url object from a URI.
    *
    * This method is for generating URLs for URIs that:
@@ -205,7 +245,7 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
    *
    * @param string $uri
    *   The URI of the resource including the scheme. For user input that may
-   *   correspond to a Drupal route, use user-path: for the scheme. For paths
+   *   correspond to a Drupal route, use internal: for the scheme. For paths
    *   that are known not to be handled by the Drupal routing system (such as
    *   static files), use base: for the scheme to get a link relative to the
    *   Drupal base path (like the <base> HTML element). For a link to an entity
@@ -227,7 +267,7 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
    *     defined, the current scheme is used, so the user stays on HTTP or HTTPS
    *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP.
    *
-   * Note: the user-path: scheme should be avoided except when processing actual
+   * Note: the internal: scheme should be avoided except when processing actual
    * user input that may or may not correspond to a Drupal route. Normally use
    * Url::fromRoute() for code linking to any any Drupal page.
    *
@@ -239,7 +279,8 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
    * @throws \InvalidArgumentException
    *   Thrown when the passed in path has no scheme.
    *
-   * @see static::fromRoute()
+   * @see \Drupal\Core\Url::fromRoute()
+   * @see \Drupal\Core\Url::fromUserInput()
    */
   public static function fromUri($uri, $options = []) {
     $uri_parts = parse_url($uri);
@@ -247,7 +288,7 @@ public static function fromUri($uri, $options = []) {
       throw new \InvalidArgumentException(String::format('The URI "@uri" is malformed.', ['@uri' => $uri]));
     }
     if (empty($uri_parts['scheme'])) {
-      throw new \InvalidArgumentException(String::format('The URI "@uri" is invalid. You must use a valid URI scheme. Use base: for items like a static file that needs the base path. Use user-path: for user input without a scheme. Use entity: for referencing the canonical route of a content entity. Use route: for directly representing a route name and parameters.', ['@uri' => $uri]));
+      throw new \InvalidArgumentException(String::format('The URI "@uri" is invalid. You must use a valid URI scheme.', ['@uri' => $uri]));
     }
     $uri_parts += ['path' => ''];
     // Discard empty fragment in $options for consistency with parse_url().
@@ -272,8 +313,8 @@ public static function fromUri($uri, $options = []) {
     if ($uri_parts['scheme'] === 'entity') {
       $url = static::fromEntityUri($uri_parts, $uri_options, $uri);
     }
-    elseif ($uri_parts['scheme'] === 'user-path') {
-      $url = static::fromUserPathUri($uri_parts, $uri_options);
+    elseif ($uri_parts['scheme'] === 'internal') {
+      $url = static::fromInternalUri($uri_parts, $uri_options);
     }
     elseif ($uri_parts['scheme'] === 'route') {
       $url = static::fromRouteUri($uri_parts, $uri_options, $uri);
@@ -317,49 +358,49 @@ protected static function fromEntityUri(array $uri_parts, array $options, $uri)
   }
 
   /**
-   * Creates a new Url object for 'user-path:' URIs.
+   * Creates a new Url object for 'internal:' URIs.
    *
    * Important note: the URI minus the scheme can NOT simply be validated by a
    * \Drupal\Core\Path\PathValidatorInterface implementation. The semantics of
-   * the 'user-path:' URI scheme are different:
+   * the 'internal:' URI scheme are different:
    * - PathValidatorInterface accepts paths without a leading slash (e.g.
    *   'node/add') as well as 2 special paths: '<front>' and '<none>', which are
    *   mapped to the correspondingly named routes.
-   * - 'user-path:' URIs store paths with a leading slash that represents the
-   *   root — i.e. the front page — (e.g. 'user-path:/node/add'), and doesn't
+   * - 'internal:' URIs store paths with a leading slash that represents the
+   *   root — i.e. the front page — (e.g. 'internal:/node/add'), and doesn't
    *   have any exceptions.
    *
-   * To clarify, a few examples of path plus corresponding 'user-path:' URI:
-   * - 'node/add' -> 'user-path:/node/add'
-   * - 'node/add?foo=bar' -> 'user-path:/node/add?foo=bar'
-   * - 'node/add#kitten' -> 'user-path:/node/add#kitten'
-   * - '<front>' -> 'user-path:/'
-   * - '<front>foo=bar' -> 'user-path:/?foo=bar'
-   * - '<front>#kitten' -> 'user-path:/#kitten'
-   * - '<none>' -> 'user-path:'
-   * - '<none>foo=bar' -> 'user-path:?foo=bar'
-   * - '<none>#kitten' -> 'user-path:#kitten'
-   *
-   * Therefore, when using a PathValidatorInterface to validate 'user-path:'
+   * To clarify, a few examples of path plus corresponding 'internal:' URI:
+   * - 'node/add' -> 'internal:/node/add'
+   * - 'node/add?foo=bar' -> 'internal:/node/add?foo=bar'
+   * - 'node/add#kitten' -> 'internal:/node/add#kitten'
+   * - '<front>' -> 'internal:/'
+   * - '<front>foo=bar' -> 'internal:/?foo=bar'
+   * - '<front>#kitten' -> 'internal:/#kitten'
+   * - '<none>' -> 'internal:'
+   * - '<none>foo=bar' -> 'internal:?foo=bar'
+   * - '<none>#kitten' -> 'internal:#kitten'
+   *
+   * Therefore, when using a PathValidatorInterface to validate 'internal:'
    * URIs, we must map:
-   * - 'user-path:' (path component is '')  to the special '<none>' path
-   * - 'user-path:/' (path component is '/') to the special '<front>' path
-   * - 'user-path:/some-path' (path component is '/some-path') to 'some-path'
+   * - 'internal:' (path component is '')  to the special '<none>' path
+   * - 'internal:/' (path component is '/') to the special '<front>' path
+   * - 'internal:/some-path' (path component is '/some-path') to 'some-path'
    *
    * @param array $uri_parts
-   *   Parts from an URI of the form user-path:{path} as from parse_url().
+   *   Parts from an URI of the form internal:{path} as from parse_url().
    * @param array $options
    *   An array of options, see static::fromUri() for details.
    *
    * @return \Drupal\Core\Url
-   *   A new Url object for a 'user-path:' URI.
+   *   A new Url object for a 'internal:' 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) {
+  protected static function fromInternalUri(array $uri_parts, array $options) {
     // Both PathValidator::getUrlIfValidWithoutAccessCheck() and 'base:' URIs
-    // only accept/contain paths without a leading slash, unlike 'user-path:'
+    // only accept/contain paths without a leading slash, unlike 'internal:'
     // URIs, for which the leading slash means "relative to Drupal root" and
     // "relative to Symfony app root" (just like in Symfony/Drupal 8 routes).
     if (empty($uri_parts['path'])) {
@@ -370,7 +411,7 @@ protected static function fromUserPathUri(array $uri_parts, array $options) {
     }
     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']]));
+        throw new \InvalidArgumentException(String::format('The internal path component "@path" is invalid. Its path component must have a leading slash, e.g. internal:/foo.', ['@path' => $uri_parts['path']]));
       }
       // Remove the leading slash.
       $uri_parts['path'] = substr($uri_parts['path'], 1);
@@ -466,7 +507,7 @@ protected function setUnrouted() {
    * Generates a URI string that represents tha data in the Url object.
    *
    * The URI will typically have the scheme of route: even if the object was
-   * constructed using an entity: or user-path: scheme. A user-path: URI that
+   * constructed using an entity: or internal: scheme. A internal: URI that
    * does not match a Drupal route with be returned here with the base: scheme,
    * and external URLs will be returned in their original form.
    *
@@ -671,7 +712,7 @@ public function setAbsolute($absolute = TRUE) {
    * string or fragment specified by the options array.
    *
    * If this Url object was constructed from a Drupal route or from an internal
-   * URI (URIs using the user-path:, base:, or entity: schemes), the returned
+   * URI (URIs using the internal:, base:, or entity: schemes), the returned
    * string will either be a relative URL like /node/1 or an absolute URL like
    * http://example.com/node/1 depending on the options array, plus any
    * specified query string or fragment.
diff --git a/core/modules/field_ui/src/FieldUI.php b/core/modules/field_ui/src/FieldUI.php
index 9ee73c7..15fd97e 100644
--- a/core/modules/field_ui/src/FieldUI.php
+++ b/core/modules/field_ui/src/FieldUI.php
@@ -61,7 +61,8 @@ public static function getNextDestination(array $destinations) {
         $options['query']['destinations'] = $destinations;
       }
       // Redirect to any given path within the same domain.
-      $next_destination = Url::fromUri('user-path:/' . $options['path']);
+      // @todo Revist this in https://www.drupal.org/node/2418219.
+      $next_destination = Url::fromUserInput('/' . $options['path']);
     }
     return $next_destination;
   }
diff --git a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
index 7546ef1..3f53efc 100644
--- a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -210,7 +210,7 @@ public function viewElements(FieldItemListInterface $items) {
           // attribute.
           // @todo Does RDF need a URL rather than an internal URI here?
           // @see \Drupal\rdf\Tests\Field\LinkFieldRdfaTest.
-          $content = str_replace('user-path:/', '', $item->uri);
+          $content = str_replace('internal:/', '', $item->uri);
           $item->_attributes += array('content' => $content);
         }
       }
diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index 0e8ebc2..f7168c3 100644
--- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -42,11 +42,11 @@ public static function defaultSettings() {
   }
 
   /**
-   * Gets the URI without the 'user-path:' or 'entity:' scheme.
+   * Gets the URI without the 'internal:' or 'entity:' scheme.
    *
    * The following two forms of URIs are transformed:
    * - 'entity:' URIs: to entity autocomplete ("label (entity id)") strings;
-   * - 'user-path:' URIs: the scheme is stripped.
+   * - 'internal:' URIs: the scheme is stripped.
    *
    * This method is the inverse of ::getUserEnteredStringAsUri().
    *
@@ -63,9 +63,9 @@ protected static function getUriAsDisplayableString($uri) {
     // By default, the displayable string is the URI.
     $displayable_string = $uri;
 
-    // A different displayable string may be chosen in case of the 'user-path:'
+    // A different displayable string may be chosen in case of the 'internal:'
     // or 'entity:' built-in schemes.
-    if ($scheme === 'user-path') {
+    if ($scheme === 'internal') {
       $uri_reference = explode(':', $uri, 2)[1];
 
       // @todo '<front>' is valid input for BC reasons, may be removed by
@@ -94,7 +94,7 @@ protected static function getUriAsDisplayableString($uri) {
    *
    * The following two forms of input are mapped to URIs:
    * - entity autocomplete ("label (entity id)") strings: to 'entity:' URIs;
-   * - strings without a detectable scheme: to 'user-path:' URIs.
+   * - strings without a detectable scheme: to 'internal:' URIs.
    *
    * This method is the inverse of ::getUriAsDisplayableString().
    *
@@ -117,7 +117,7 @@ protected static function getUserEnteredStringAsUri($string) {
       //    https://www.drupal.org/node/2423093.
       $uri = 'entity:node/' . $entity_id;
     }
-    // Detect a schemeless string, map to 'user-path:' URI.
+    // Detect a schemeless string, map to 'internal:' URI.
     elseif (!empty($string) && parse_url($string, PHP_URL_SCHEME) === NULL) {
       // @todo '<front>' is valid input for BC reasons, may be removed by
       //   https://www.drupal.org/node/2421941
@@ -126,7 +126,7 @@ protected static function getUserEnteredStringAsUri($string) {
       if (strpos($string, '<front>') === 0) {
         $string = '/' . substr($string, strlen('<front>'));
       }
-      $uri = 'user-path:' . $string;
+      $uri = 'internal:' . $string;
     }
 
     return $uri;
@@ -139,11 +139,11 @@ public static function validateUriElement($element, FormStateInterface $form_sta
     $uri = static::getUserEnteredStringAsUri($element['#value']);
     $form_state->setValueForElement($element, $uri);
 
-    // If getUserEnteredStringAsUri() mapped the entered value to a 'user-path:'
+    // If getUserEnteredStringAsUri() mapped the entered value to a 'internal:'
     // URI , ensure the raw value begins with '/', '?' or '#'.
     // @todo '<front>' is valid input for BC reasons, may be removed by
     //   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>') {
+    if (parse_url($uri, PHP_URL_SCHEME) === 'internal' && !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;
     }
@@ -363,7 +363,7 @@ public function massageFormValues(array $values, array $form, FormStateInterface
   /**
    * {@inheritdoc}
    *
-   * Override the '%uri' message parameter, to ensure that 'user-path:' URIs
+   * Override the '%uri' message parameter, to ensure that 'internal:' URIs
    * show a validation error message that doesn't mention that scheme.
    */
   public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
diff --git a/core/modules/menu_link_content/menu_link_content.module b/core/modules/menu_link_content/menu_link_content.module
index 3a034a0..aedde3e 100644
--- a/core/modules/menu_link_content/menu_link_content.module
+++ b/core/modules/menu_link_content/menu_link_content.module
@@ -45,7 +45,7 @@ function menu_link_content_path_insert($path) {
 }
 
 /**
- * Helper function to update plugin definition using user-path scheme.
+ * Helper function to update plugin definition using internal scheme.
  *
  * @param string $path
  *   The path alias.
@@ -57,7 +57,7 @@ function _menu_link_content_update_path_alias($path) {
   /** @var \Drupal\menu_link_content\MenuLinkContentInterface[] $entities */
   $entities = \Drupal::entityManager()
     ->getStorage('menu_link_content')
-    ->loadByProperties(['link.uri' => 'user-path:/' . $path]);
+    ->loadByProperties(['link.uri' => 'internal:/' . $path]);
   foreach ($entities as $menu_link) {
     $menu_link_manager->updateDefinition($menu_link->getPluginId(), $menu_link->getPluginDefinition(), FALSE);
   }
diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
index 24e5dd9..78d7483 100644
--- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -186,7 +186,7 @@ public static function preCreate(EntityStorageInterface $storage, array &$values
   public function preSave(EntityStorageInterface $storage) {
     parent::preSave($storage);
 
-    if (parse_url($this->link->uri, PHP_URL_SCHEME) === 'user-path') {
+    if (parse_url($this->link->uri, PHP_URL_SCHEME) === 'internal') {
       $this->setRequiresRediscovery(TRUE);
     }
     else {
diff --git a/core/modules/menu_link_content/src/Tests/LinksTest.php b/core/modules/menu_link_content/src/Tests/LinksTest.php
index f7500ee..92f18b6 100644
--- a/core/modules/menu_link_content/src/Tests/LinksTest.php
+++ b/core/modules/menu_link_content/src/Tests/LinksTest.php
@@ -67,14 +67,14 @@ function createLinkHierarchy($module = 'menu_test') {
     );
 
     $parent = $base_options + array(
-      'link' => ['uri' => 'user-path:/menu-test/hierarchy/parent'],
+      'link' => ['uri' => 'internal:/menu-test/hierarchy/parent'],
     );
     $link = entity_create('menu_link_content', $parent);
     $link->save();
     $links['parent'] = $link->getPluginId();
 
     $child_1 = $base_options + array(
-      'link' => ['uri' => 'user-path:/menu-test/hierarchy/parent/child'],
+      'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child'],
       'parent' => $links['parent'],
     );
     $link = entity_create('menu_link_content', $child_1);
@@ -82,7 +82,7 @@ function createLinkHierarchy($module = 'menu_test') {
     $links['child-1'] = $link->getPluginId();
 
     $child_1_1 = $base_options + array(
-      'link' => ['uri' => 'user-path:/menu-test/hierarchy/parent/child2/child'],
+      'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child2/child'],
       'parent' => $links['child-1'],
     );
     $link = entity_create('menu_link_content', $child_1_1);
@@ -90,7 +90,7 @@ function createLinkHierarchy($module = 'menu_test') {
     $links['child-1-1'] = $link->getPluginId();
 
     $child_1_2 = $base_options + array(
-      'link' => ['uri' => 'user-path:/menu-test/hierarchy/parent/child2/child'],
+      'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child2/child'],
       'parent' => $links['child-1'],
     );
     $link = entity_create('menu_link_content', $child_1_2);
@@ -98,7 +98,7 @@ function createLinkHierarchy($module = 'menu_test') {
     $links['child-1-2'] = $link->getPluginId();
 
     $child_2 = $base_options + array(
-      'link' => ['uri' => 'user-path:/menu-test/hierarchy/parent/child'],
+      'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child'],
       'parent' => $links['parent'],
     );
     $link = entity_create('menu_link_content', $child_2);
@@ -128,7 +128,7 @@ public function testCreateLink() {
     $options = array(
       'menu_name' => 'menu_test',
       'bundle' => 'menu_link_content',
-      'link' => [['uri' => 'user-path:/']],
+      'link' => [['uri' => 'internal:/']],
     );
     $link = entity_create('menu_link_content', $options);
     $link->save();
diff --git a/core/modules/menu_link_content/src/Tests/MenuLinkContentDeriverTest.php b/core/modules/menu_link_content/src/Tests/MenuLinkContentDeriverTest.php
index aaf2e7f..c7a1ae1 100644
--- a/core/modules/menu_link_content/src/Tests/MenuLinkContentDeriverTest.php
+++ b/core/modules/menu_link_content/src/Tests/MenuLinkContentDeriverTest.php
@@ -46,7 +46,7 @@ public function testRediscover() {
     // Set up a custom menu link pointing to a specific path.
     MenuLinkContent::create([
       'title' => 'Example',
-      'link' => [['uri' => 'user-path:/example-path']],
+      'link' => [['uri' => 'internal:/example-path']],
       'menu_name' => 'tools',
     ])->save();
     $menu_tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters());
diff --git a/core/modules/menu_link_content/src/Tests/MenuLinkContentUITest.php b/core/modules/menu_link_content/src/Tests/MenuLinkContentUITest.php
index 94fbf32..ab4c62a 100644
--- a/core/modules/menu_link_content/src/Tests/MenuLinkContentUITest.php
+++ b/core/modules/menu_link_content/src/Tests/MenuLinkContentUITest.php
@@ -57,7 +57,7 @@ protected function getAdministratorPermissions() {
    */
   protected function createEntity($values, $langcode, $bundle_name = NULL) {
     $values['menu_name'] = 'tools';
-    $values['link']['uri'] = 'user-path:/admin/structure/menu';
+    $values['link']['uri'] = 'internal:/admin/structure/menu';
     $values['title'] = 'Test title';
 
     return parent::createEntity($values, $langcode, $bundle_name);
@@ -70,7 +70,7 @@ public function testTranslationLinkOnMenuEditForm() {
     $this->drupalGet('admin/structure/menu/manage/tools');
     $this->assertNoLink(t('Translate'));
 
-    $menu_link_content = MenuLinkContent::create(['menu_name' => 'tools', 'link' => ['uri' => 'user-path:/admin/structure/menu']]);
+    $menu_link_content = MenuLinkContent::create(['menu_name' => 'tools', 'link' => ['uri' => 'internal:/admin/structure/menu']]);
     $menu_link_content->save();
     $this->drupalGet('admin/structure/menu/manage/tools');
     $this->assertLink(t('Translate'));
diff --git a/core/modules/menu_link_content/src/Tests/PathAliasMenuLinkContentTest.php b/core/modules/menu_link_content/src/Tests/PathAliasMenuLinkContentTest.php
index af965af..3caf26f 100644
--- a/core/modules/menu_link_content/src/Tests/PathAliasMenuLinkContentTest.php
+++ b/core/modules/menu_link_content/src/Tests/PathAliasMenuLinkContentTest.php
@@ -64,7 +64,7 @@ public function testPathAliasChange() {
 
     $menu_link_content = MenuLinkContent::create([
       'title' => 'Menu title',
-      'link' => ['uri' => 'user-path:/my-blog'],
+      'link' => ['uri' => 'internal:/my-blog'],
       'menu_name' => 'tools',
     ]);
     $menu_link_content->save();
diff --git a/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php b/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
index b332f123..40477f0 100644
--- a/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
@@ -83,7 +83,7 @@ public function testMenuBlock() {
       'title' => 'Alpaca',
       'menu_name' => 'llama',
       'link' => [[
-        'uri' => 'user-path:/',
+        'uri' => 'internal:/',
       ]],
       'bundle' => 'menu_name',
     ));
diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php
index c38f25f..71bfd73 100644
--- a/core/modules/menu_ui/src/Tests/MenuTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuTest.php
@@ -105,8 +105,8 @@ function testMenu() {
     $this->verifyAccess(403);
 
     foreach ($this->items as $item) {
-      // Menu link URIs are stored as 'user-path:/node/$nid'.
-      $node = Node::load(str_replace('user-path:/node/', '', $item->link->uri));
+      // Menu link URIs are stored as 'internal:/node/$nid'.
+      $node = Node::load(str_replace('internal:/node/', '', $item->link->uri));
       $this->verifyMenuLink($item, $node);
     }
 
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_menu_links.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_menu_links.yml
index 41b7fa3..0d443a6 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_menu_links.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_menu_links.yml
@@ -23,7 +23,7 @@ process:
     migration: d6_menu
     source: menu_name
   'link/uri':
-    plugin: userpath_uri
+    plugin: internal_uri
     source:
       - link_path
   'link/options': options
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/process/d6/UserPathUri.php b/core/modules/migrate_drupal/src/Plugin/migrate/process/d6/InternalUri.php
similarity index 68%
rename from core/modules/migrate_drupal/src/Plugin/migrate/process/d6/UserPathUri.php
rename to core/modules/migrate_drupal/src/Plugin/migrate/process/d6/InternalUri.php
index ade7f8c..bcbac21 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/process/d6/UserPathUri.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/process/d6/InternalUri.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\UserPathUri.
+ * Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\InternalUri.
  */
 
 namespace Drupal\migrate_drupal\Plugin\migrate\process\d6;
@@ -12,13 +12,13 @@
 use Drupal\migrate\Row;
 
 /**
- * Process a path into a 'user-path:' URI.
+ * Process a path into an 'internal:' URI.
  *
  * @MigrateProcessPlugin(
- *   id = "userpath_uri"
+ *   id = "internal_uri"
  * )
  */
-class UserPathUri extends ProcessPluginBase {
+class InternalUri extends ProcessPluginBase {
 
   /**
    * {@inheritdoc}
@@ -27,7 +27,7 @@ public function transform($value, MigrateExecutable $migrate_executable, Row $ro
     list($path) = $value;
 
     if (parse_url($path, PHP_URL_SCHEME) === NULL) {
-      return 'user-path:/' . $path;
+      return 'internal:/' . $path;
     }
     return $path;
   }
diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuLinkTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuLinkTest.php
index 8ccf3f1..023c5cd 100644
--- a/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuLinkTest.php
+++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuLinkTest.php
@@ -57,7 +57,7 @@ public function testMenuLinks() {
     $this->assertIdentical($menu_link->isEnabled(), TRUE);
     $this->assertIdentical($menu_link->isExpanded(), FALSE);
     $this->assertIdentical($menu_link->link->options, ['attributes' => ['title' => 'Test menu link 1']]);
-    $this->assertIdentical($menu_link->link->uri, 'user-path:/user/login');
+    $this->assertIdentical($menu_link->link->uri, 'internal:/user/login');
     $this->assertIdentical($menu_link->getWeight(), 15);
 
     $menu_link = entity_load('menu_link_content', 139);
@@ -67,7 +67,7 @@ public function testMenuLinks() {
     $this->assertIdentical($menu_link->isEnabled(), TRUE);
     $this->assertIdentical($menu_link->isExpanded(), TRUE);
     $this->assertIdentical($menu_link->link->options, ['query' => 'foo=bar', 'attributes' => ['title' => 'Test menu link 2']]);
-    $this->assertIdentical($menu_link->link->uri, 'user-path:/admin');
+    $this->assertIdentical($menu_link->link->uri, 'internal:/admin');
     $this->assertIdentical($menu_link->getWeight(), 12);
 
     $menu_link = entity_load('menu_link_content', 140);
diff --git a/core/modules/path/src/Controller/PathController.php b/core/modules/path/src/Controller/PathController.php
index a43939e..e144c37 100644
--- a/core/modules/path/src/Controller/PathController.php
+++ b/core/modules/path/src/Controller/PathController.php
@@ -86,10 +86,11 @@ public function adminOverview(Request $request) {
     $destination = drupal_get_destination();
     foreach ($this->aliasStorage->getAliasesForAdminListing($header, $keys) as $data) {
       $row = array();
-      $row['data']['alias'] = $this->l(Unicode::truncate($data->alias, 50, FALSE, TRUE), Url::fromUri('user-path:/' . $data->source, array(
+      // @todo Should Path module store leading slashes? Needs followup.
+      $row['data']['alias'] = $this->l(Unicode::truncate($data->alias, 50, FALSE, TRUE), Url::fromUserInput('/' . $data->source, array(
         'attributes' => array('title' => $data->alias),
       )));
-      $row['data']['source'] = $this->l(Unicode::truncate($data->source, 50, FALSE, TRUE), Url::fromUri('user-path:/' . $data->source, array(
+      $row['data']['source'] = $this->l(Unicode::truncate($data->source, 50, FALSE, TRUE), Url::fromUserInput('/' . $data->source, array(
         'alias' => TRUE,
         'attributes' => array('title' => $data->source),
       )));
diff --git a/core/modules/rdf/src/Tests/Field/LinkFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/LinkFieldRdfaTest.php
index 34db4c5..4d643d0 100644
--- a/core/modules/rdf/src/Tests/Field/LinkFieldRdfaTest.php
+++ b/core/modules/rdf/src/Tests/Field/LinkFieldRdfaTest.php
@@ -67,7 +67,7 @@ public function testAllFormattersInternal() {
     // Set up test values.
     $this->testValue = 'admin';
     $this->entity = entity_create('entity_test', array());
-    $this->entity->{$this->fieldName}->uri = 'user-path:/admin';
+    $this->entity->{$this->fieldName}->uri = 'internal:/admin';
 
     // Set up the expected result.
     // AssertFormatterRdfa looks for a full path.
@@ -86,7 +86,7 @@ public function testAllFormattersFront() {
     // Set up test values.
     $this->testValue = '/';
     $this->entity = entity_create('entity_test', array());
-    $this->entity->{$this->fieldName}->uri = 'user-path:/';
+    $this->entity->{$this->fieldName}->uri = 'internal:/';
 
     // Set up the expected result.
     $expected_rdf = array(
diff --git a/core/modules/shortcut/src/Controller/ShortcutSetController.php b/core/modules/shortcut/src/Controller/ShortcutSetController.php
index 528b02d..6a30d7c 100644
--- a/core/modules/shortcut/src/Controller/ShortcutSetController.php
+++ b/core/modules/shortcut/src/Controller/ShortcutSetController.php
@@ -65,7 +65,7 @@ public function addShortcutLinkInline(ShortcutSetInterface $shortcut_set, Reques
         'title' => $name,
         'shortcut_set' => $shortcut_set->id(),
         'link' => array(
-          'uri' => 'user-path:/' . $link,
+          'uri' => 'internal:/' . $link,
         ),
       ));
 
diff --git a/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php b/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php
index 5265745..c67e0d0 100644
--- a/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php
@@ -46,7 +46,7 @@ protected function createEntity() {
       'shortcut_set' => 'default',
       'title' => t('Llama'),
       'weight' => 0,
-      'link' => [['uri' => 'user-path:/admin']],
+      'link' => [['uri' => 'internal:/admin']],
     ));
     $shortcut->save();
 
diff --git a/core/modules/shortcut/src/Tests/ShortcutLinksTest.php b/core/modules/shortcut/src/Tests/ShortcutLinksTest.php
index 5da80ae..a59e5d5 100644
--- a/core/modules/shortcut/src/Tests/ShortcutLinksTest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutLinksTest.php
@@ -66,7 +66,7 @@ public function testShortcutLinkAdd() {
       $this->assertResponse(200);
       $saved_set = ShortcutSet::load($set->id());
       $paths = $this->getShortcutInformation($saved_set, 'link');
-      $this->assertTrue(in_array('user-path:' . $test_path, $paths), 'Shortcut created: ' . $test_path);
+      $this->assertTrue(in_array('internal:' . $test_path, $paths), 'Shortcut created: ' . $test_path);
 
       if (in_array($test_path, $test_cases_non_access)) {
         $this->assertNoLink($title, String::format('Shortcut link %url not accessible on the page.', ['%url' => $test_path]));
@@ -168,7 +168,7 @@ public function testShortcutLinkChangePath() {
     $this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id(), array('title[0][value]' => $shortcut->getTitle(), 'link[0][uri]' => $new_link_path), t('Save'));
     $saved_set = ShortcutSet::load($set->id());
     $paths = $this->getShortcutInformation($saved_set, 'link');
-    $this->assertTrue(in_array('user-path:' . $new_link_path, $paths), 'Shortcut path changed: ' . $new_link_path);
+    $this->assertTrue(in_array('internal:' . $new_link_path, $paths), 'Shortcut path changed: ' . $new_link_path);
     $this->assertLinkByHref($new_link_path, 0, 'Shortcut with new path appears on the page.');
   }
 
diff --git a/core/modules/shortcut/src/Tests/ShortcutTestBase.php b/core/modules/shortcut/src/Tests/ShortcutTestBase.php
index ae1b24a..eabfbed 100644
--- a/core/modules/shortcut/src/Tests/ShortcutTestBase.php
+++ b/core/modules/shortcut/src/Tests/ShortcutTestBase.php
@@ -66,7 +66,7 @@ protected function setUp() {
         'title' => t('Add content'),
         'weight' => -20,
         'link' => array(
-          'uri' => 'user-path:/node/add',
+          'uri' => 'internal:/node/add',
         ),
       ));
       $shortcut->save();
@@ -76,7 +76,7 @@ protected function setUp() {
         'title' => t('All content'),
         'weight' => -19,
         'link' => array(
-          'uri' => 'user-path:/admin/content',
+          'uri' => 'internal:/admin/content',
         ),
       ));
       $shortcut->save();
diff --git a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
index 41b4f8d..9f81cb5 100644
--- a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
@@ -50,7 +50,7 @@ protected function getTranslatorPermissions() {
    * {@inheritdoc}
    */
   protected function createEntity($values, $langcode, $bundle_name = NULL) {
-    $values['link']['uri'] = 'user-path:/user';
+    $values['link']['uri'] = 'internal:/user';
     return parent::createEntity($values, $langcode, $bundle_name);
   }
 
diff --git a/core/modules/system/src/Tests/Common/UrlTest.php b/core/modules/system/src/Tests/Common/UrlTest.php
index 4511c8e..6beeb31 100644
--- a/core/modules/system/src/Tests/Common/UrlTest.php
+++ b/core/modules/system/src/Tests/Common/UrlTest.php
@@ -31,7 +31,7 @@ function testLinkXSS() {
     // Test \Drupal::l().
     $text = $this->randomMachineName();
     $path = "<SCRIPT>alert('XSS')</SCRIPT>";
-    $link = \Drupal::l($text, Url::fromUri('user-path:/' . $path));
+    $link = \Drupal::l($text, Url::fromUserInput('/' . $path));
     $sanitized_path = check_url(Url::fromUri('base:' . $path)->toString());
     $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by _l().', array('@path' => $path)));
 
diff --git a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
index 6e54308..59f0901 100644
--- a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
+++ b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
@@ -247,7 +247,7 @@ function testBreadCrumbs() {
       $this->drupalPostForm("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
       $menu_links = entity_load_multiple_by_properties('menu_link_content', array(
         'title' => $edit['title[0][value]'],
-        'link.uri' => 'user-path:/taxonomy/term/' . $term->id(),
+        'link.uri' => 'internal:/taxonomy/term/' . $term->id(),
       ));
       $tags[$name]['link'] = reset($menu_links);
       $parent_mlid = $tags[$name]['link']->getPluginId();
diff --git a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
index 0ec8dfd..1dbca60 100644
--- a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
@@ -67,9 +67,9 @@ public function testDeleteLinksInMenu() {
     \Drupal::entityManager()->getStorage('menu')->create(array('id' => 'menu1'))->save();
     \Drupal::entityManager()->getStorage('menu')->create(array('id' => 'menu2'))->save();
 
-    \Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'user-path:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'))->save();
-    \Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'user-path:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'))->save();
-    \Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'user-path:/menu_name_test'], 'menu_name' => 'menu2', 'bundle' => 'menu_link_content'))->save();
+    \Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'))->save();
+    \Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'))->save();
+    \Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu2', 'bundle' => 'menu_link_content'))->save();
 
     $output = $this->linkTree->load('menu1', new MenuTreeParameters());
     $this->assertEqual(count($output), 2);
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php
index c1b0a83..e366db3 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php
@@ -55,7 +55,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     if (!$form_state->isValueEmpty('redirection')) {
       if (!$form_state->isValueEmpty('destination')) {
         // The destination is a random URL, so we can't use routed URLs.
-        $form_state->setRedirectUrl(Url::fromUri('user-path:/' . $form_state->getValue('destination')));
+        // @todo Revist this in https://www.drupal.org/node/2418219.
+        $form_state->setRedirectUrl(Url::fromUserInput('/' . $form_state->getValue('destination')));
       }
     }
     else {
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 267a423..6c3a819 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -2060,7 +2060,9 @@ public function renderMoreLink() {
       if ($this->getOption('link_display') == 'custom_url' && $override_path = $this->getOption('link_url')) {
         $tokens = $this->getArgumentsTokens();
         $path = $this->viewsTokenReplace($override_path, $tokens);
-        $url = Url::fromUri('user-path:/' . $path);
+        // @todo Views should expect and store a leading /. See:
+        //   https://www.drupal.org/node/2423913
+        $url = Url::fromUserInput('/' . $path);
       }
       // Otherwise, use the URL for the display.
       else {
diff --git a/core/modules/views/src/Plugin/views/display/PathPluginBase.php b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
index ed49009..c4cc43f 100644
--- a/core/modules/views/src/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
@@ -456,7 +456,7 @@ protected function validatePath($path) {
       $errors[] = $this->t('No query allowed.');
     }
 
-    if (!parse_url('user-path:/' . $path)) {
+    if (!parse_url('internal:/' . $path)) {
       $errors[] = $this->t('Invalid path. Valid characters are alphanumerics as well as "-", ".", "_" and "~".');
     }
 
diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
index 698e5d8..28cdcd1 100644
--- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
@@ -1248,7 +1248,9 @@ public function renderText($alter) {
           $more_link_path = Unicode::substr($more_link_path, Unicode::strlen($base_path));
         }
 
-        $more_link = \Drupal::l($more_link_text, CoreUrl::fromUri('user-path:/' . $more_link_path), array('attributes' => array('class' => array('views-more-link'))));
+        // @todo Views should expect and store a leading /. See:
+        //   https://www.drupal.org/node/2423913
+        $more_link = \Drupal::l($more_link_text, CoreUrl::fromUserInput('/' . $more_link_path), array('attributes' => array('class' => array('views-more-link'))));
 
         $suffix .= " " . $more_link;
       }
@@ -1313,7 +1315,9 @@ protected function renderAsLink($alter, $text, $tokens) {
     $path = $alter['path'];
     if (empty($alter['url'])) {
       if (!parse_url($path, PHP_URL_SCHEME)) {
-        $alter['url'] = CoreUrl::fromUri('user-path:/' . ltrim($path, '/'));
+        // @todo Views should expect and store a leading /. See:
+        //   https://www.drupal.org/node/2423913
+        $alter['url'] = CoreUrl::fromUserInput('/' . ltrim($path, '/'));
       }
       else {
         $alter['url'] = CoreUrl::fromUri($path);
@@ -1330,7 +1334,7 @@ protected function renderAsLink($alter, $text, $tokens) {
       // Url::toUriString() call above, because we support twig tokens in
       // rewrite settings of views fields.
       // In that case the original path looks like
-      // user-path:/admin/content/files/usage/{{ fid }}, which will be escaped by
+      // internal:/admin/content/files/usage/{{ fid }}, which will be escaped by
       // the toUriString() call above.
       $path = preg_replace(['/(\%7B){2}(\%20)*/', '/(\%20)*(\%7D){2}/'], ['{{','}}'], $path);
 
diff --git a/core/modules/views/src/Plugin/views/field/Links.php b/core/modules/views/src/Plugin/views/field/Links.php
index e6ef344..2302778 100644
--- a/core/modules/views/src/Plugin/views/field/Links.php
+++ b/core/modules/views/src/Plugin/views/field/Links.php
@@ -85,7 +85,7 @@ protected function getLinks() {
       $path = strip_tags(String::decodeEntities($this->viewsTokenReplace($path, $tokens)));
 
       $links[$field] = array(
-        'url' => $path ? UrlObject::fromUri('user-path:/' . $path) : $url,
+        'url' => $path ? UrlObject::fromUri('internal:/' . $path) : $url,
         'title' => $title,
       );
       if (!empty($this->options['destination'])) {
diff --git a/core/modules/views/src/Plugin/views/field/Url.php b/core/modules/views/src/Plugin/views/field/Url.php
index 7f3aa29..c162fb1 100644
--- a/core/modules/views/src/Plugin/views/field/Url.php
+++ b/core/modules/views/src/Plugin/views/field/Url.php
@@ -49,7 +49,9 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
   public function render(ResultRow $values) {
     $value = $this->getValue($values);
     if (!empty($this->options['display_as_link'])) {
-      return \Drupal::l($this->sanitizeValue($value), CoreUrl::fromUri('user-path:/' . $value), array('html' => TRUE));
+      // @todo Views should expect and store a leading /. See:
+      //   https://www.drupal.org/node/2423913
+      return \Drupal::l($this->sanitizeValue($value), CoreUrl::fromUserInput('/' . $value), array('html' => TRUE));
     }
     else {
       return $this->sanitizeValue($value, 'url');
diff --git a/core/modules/views/src/Plugin/views/row/RssFields.php b/core/modules/views/src/Plugin/views/row/RssFields.php
index 82b1212..ec7f5e2 100644
--- a/core/modules/views/src/Plugin/views/row/RssFields.php
+++ b/core/modules/views/src/Plugin/views/row/RssFields.php
@@ -144,7 +144,9 @@ public function render($row) {
     // Create the RSS item object.
     $item = new \stdClass();
     $item->title = $this->getField($row_index, $this->options['title_field']);
-    $item->link = Url::fromUri('user-path:/' . $this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString();
+    // @todo Views should expect and store a leading /. See:
+    //   https://www.drupal.org/node/2423913
+    $item->link = Url::fromUserInput('/' . $this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString();
     $item->description = $this->getField($row_index, $this->options['description_field']);
     $item->elements = array(
       array('key' => 'pubDate', 'value' => $this->getField($row_index, $this->options['date_field'])),
@@ -158,7 +160,9 @@ public function render($row) {
     $item_guid = $this->getField($row_index, $this->options['guid_field_options']['guid_field']);
     if ($this->options['guid_field_options']['guid_field_is_permalink']) {
       $guid_is_permalink_string = 'true';
-      $item_guid = Url::fromUri('user-path:/' . $item_guid)->setAbsolute()->toString();
+      // @todo Views should expect and store a leading /. See:
+      //   https://www.drupal.org/node/2423913
+      $item_guid = Url::fromUserInput('/' . $item_guid)->setAbsolute()->toString();
     }
     $item->elements[] = array(
       'key' => 'guid',
diff --git a/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php b/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php
index 537d86b..219ebda 100644
--- a/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php
+++ b/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php
@@ -50,7 +50,7 @@ public function testEntityOperations() {
     foreach ($entities as $entity) {
       $operations = \Drupal::entityManager()->getListBuilder('entity_test')->getOperations($entity);
       foreach ($operations as $operation) {
-        $expected_destination = Url::fromUri('user-path:/test-entity-operations');
+        $expected_destination = Url::fromUri('internal:/test-entity-operations');
         $result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', array(':path' => $operation['url'] . '?destination=' . $expected_destination, ':title' => $operation['title']));
         $this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', array('@operation' => $operation['title'])));
       }
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 68a38bc..748a153 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -328,7 +328,9 @@ function template_preprocess_views_view_summary(&$variables) {
       $base_path = $argument->options['summary_options']['base_path'];
       $tokens = $this->getArgumentsTokens();
       $base_path = $this->viewsTokenReplace($base_path, $tokens);
-      $url = Url::fromUri('user-path:/' . $base_path);
+      // @todo Views should expect and store a leading /. See:
+      //   https://www.drupal.org/node/2423913
+      $url = Url::fromUserInput('/' . $base_path);
     }
     else {
       $url = $view->getUrl($args)->setOptions($url_options);
@@ -395,7 +397,9 @@ function template_preprocess_views_view_summary_unformatted(&$variables) {
       $base_path = $argument->options['summary_options']['base_path'];
       $tokens = $this->getArgumentsTokens();
       $base_path = $this->viewsTokenReplace($base_path, $tokens);
-      $url = Url::fromUri('user-path:/' . $base_path);
+      // @todo Views should expect and store a leading /. See:
+      //   https://www.drupal.org/node/2423913
+      $url = Url::fromUserInput('/' . $base_path);
     }
     else {
       $url = $view->getUrl($args)->setOptions($url_options);
@@ -876,7 +880,9 @@ function template_preprocess_views_view_rss(&$variables) {
     // Compare the link to the default home page; if it's the default home page,
     // just use $base_url.
     $url_string = $url->setOptions($url_options)->toString();
-    if ($url_string === Url::fromUri('user-path:/' . $config->get('page.front'))->toString()) {
+    // @todo Views should expect and store a leading /. See:
+    //   https://www.drupal.org/node/2423913
+    if ($url_string === Url::fromUserInput('/' . $config->get('page.front'))->toString()) {
       $url_string = Url::fromRoute('<front>')->setAbsolute()->toString();
     }
 
diff --git a/core/modules/views_ui/src/ViewListBuilder.php b/core/modules/views_ui/src/ViewListBuilder.php
index 04a9e9a..3463177 100644
--- a/core/modules/views_ui/src/ViewListBuilder.php
+++ b/core/modules/views_ui/src/ViewListBuilder.php
@@ -264,7 +264,9 @@ protected function getDisplayPaths(EntityInterface $view) {
       if ($display->hasPath()) {
         $path = $display->getPath();
         if ($view->status() && strpos($path, '%') === FALSE) {
-          $all_paths[] = \Drupal::l('/' . $path, Url::fromUri('user-path:/' . $path));
+          // @todo Views should expect and store a leading /. See:
+          //   https://www.drupal.org/node/2423913
+          $all_paths[] = \Drupal::l('/' . $path, Url::fromUserInput('/' . $path));
         }
         else {
           $all_paths[] = String::checkPlain('/' . $path);
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 08e887c..52c7928 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -723,7 +723,9 @@ public function renderPreview($display_id, $args = array()) {
               Xss::filterAdmin($this->executable->getTitle()),
             );
             if (isset($path)) {
-              $path = \Drupal::l($path, Url::fromUri('user-path:/' . $path));
+              // @todo Views should expect and store a leading /. See:
+              //   https://www.drupal.org/node/2423913
+              $path = \Drupal::l($path, Url::fromUserInput('/' . $path));
             }
             else {
               $path = t('This display has no path.');
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index f9466ff..4f51f8a 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -58,7 +58,7 @@ function standard_install() {
     'shortcut_set' => 'default',
     'title' => t('Add content'),
     'weight' => -20,
-    'link' => array('uri' => 'user-path:/node/add'),
+    'link' => array('uri' => 'internal:/node/add'),
   ));
   $shortcut->save();
 
@@ -66,7 +66,7 @@ function standard_install() {
     'shortcut_set' => 'default',
     'title' => t('All content'),
     'weight' => -19,
-    'link' => array('uri' => 'user-path:/admin/content'),
+    'link' => array('uri' => 'internal:/admin/content'),
   ));
   $shortcut->save();
 
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index d57ae8b..98c8f36 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Tests\Core;
 
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Routing\RouteMatch;
@@ -171,6 +172,49 @@ public function testFromRouteFront() {
   }
 
   /**
+   * Tests the fromUserInput method with valid paths.
+   *
+   * @covers ::fromUserInput
+   * @dataProvider providerFromValidInternalUri
+   */
+  public function testFromUserInput($path) {
+    $url = Url::fromUserInput($path);
+    $uri = $url->getUri();
+
+    $this->assertInstanceOf('Drupal\Core\Url', $url);
+    $this->assertFalse($url->isRouted());
+    $this->assertEquals(0, strpos($uri, 'base:'));
+
+    $parts = UrlHelper::parse($path);
+    $options = $url->getOptions();
+
+    if (!empty($parts['fragment'])) {
+      $this->assertSame($parts['fragment'], $options['fragment']);
+    }
+    else {
+      $this->assertArrayNotHasKey('fragment', $options);
+    }
+
+    if (!empty($parts['query'])) {
+      $this->assertEquals($parts['query'], $options['query']);
+    }
+    else {
+      $this->assertArrayNotHasKey('query', $options);
+    }
+  }
+
+  /**
+   * Tests the fromUserInput method with invalid paths.
+   *
+   * @covers ::fromUserInput
+   * @expectedException \InvalidArgumentException
+   * @dataProvider providerFromInvalidInternalUri
+   */
+  public function testFromInvalidUserInput($path) {
+    $url = Url::fromUserInput($path);
+  }
+
+  /**
    * Tests fromUri() method with a user-entered path not matching any route.
    *
    * @covers ::fromUri
@@ -180,7 +224,7 @@ public function testFromRoutedPathWithInvalidRoute() {
       ->method('getUrlIfValidWithoutAccessCheck')
       ->with('invalid-path')
       ->willReturn(FALSE);
-    $url = Url::fromUri('user-path:/invalid-path');
+    $url = Url::fromUri('internal:/invalid-path');
     $this->assertSame(FALSE, $url->isRouted());
     $this->assertSame('base:invalid-path', $url->getUri());
   }
@@ -196,7 +240,7 @@ public function testFromRoutedPathWithValidRoute() {
       ->method('getUrlIfValidWithoutAccessCheck')
       ->with('valid-path')
       ->willReturn($url);
-    $result_url = Url::fromUri('user-path:/valid-path');
+    $result_url = Url::fromUri('internal:/valid-path');
     $this->assertSame($url, $result_url);
   }
 
@@ -592,13 +636,13 @@ public function providerTestToUriStringForEntity() {
   }
 
   /**
-   * Tests the toUriString() method with user-path: URIs.
+   * Tests the toUriString() method with internal: URIs.
    *
    * @covers ::toUriString
    *
-   * @dataProvider providerTestToUriStringForUserPath
+   * @dataProvider providerTestToUriStringForInternal
    */
-  public function testToUriStringForUserPath($uri, $options, $uri_string) {
+  public function testToUriStringForInternal($uri, $options, $uri_string) {
     $url = Url::fromRoute('entity.test_entity.canonical', ['test_entity' => '1']);
     $this->pathValidator->expects($this->any())
       ->method('getUrlIfValidWithoutAccessCheck')
@@ -612,45 +656,45 @@ public function testToUriStringForUserPath($uri, $options, $uri_string) {
   }
 
   /**
-   * Data provider for testing user-path URIs
+   * Data provider for testing internal URIs.
    */
-  public function providerTestToUriStringForUserPath() {
+  public function providerTestToUriStringForInternal() {
     return [
       // The four permutations of a regular path.
-      ['user-path:/test-entity/1', [], 'route:entity.test_entity.canonical;test_entity=1'],
-      ['user-path:/test-entity/1', ['fragment' => 'top'], 'route:entity.test_entity.canonical;test_entity=1#top'],
-      ['user-path:/test-entity/1', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'],
-      ['user-path:/test-entity/1?page=2#top', [], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'],
+      ['internal:/test-entity/1', [], 'route:entity.test_entity.canonical;test_entity=1'],
+      ['internal:/test-entity/1', ['fragment' => 'top'], 'route:entity.test_entity.canonical;test_entity=1#top'],
+      ['internal:/test-entity/1', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'],
+      ['internal:/test-entity/1?page=2#top', [], 'route:entity.test_entity.canonical;test_entity=1?page=2#top'],
 
       // The four permutations of the special '<front>' path.
-      ['user-path:/', [], 'route:<front>'],
-      ['user-path:/', ['fragment' => 'top'], 'route:<front>#top'],
-      ['user-path:/', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:<front>?page=2#top'],
-      ['user-path:/?page=2#top', [], 'route:<front>?page=2#top'],
+      ['internal:/', [], 'route:<front>'],
+      ['internal:/', ['fragment' => 'top'], 'route:<front>#top'],
+      ['internal:/', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:<front>?page=2#top'],
+      ['internal:/?page=2#top', [], 'route:<front>?page=2#top'],
 
       // The four permutations of the special '<none>' path.
-      ['user-path:', [], 'route:<none>'],
-      ['user-path:', ['fragment' => 'top'], 'route:<none>#top'],
-      ['user-path:', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:<none>?page=2#top'],
-      ['user-path:?page=2#top', [], 'route:<none>?page=2#top'],
+      ['internal:', [], 'route:<none>'],
+      ['internal:', ['fragment' => 'top'], 'route:<none>#top'],
+      ['internal:', ['fragment' => 'top', 'query' => ['page' => '2']], 'route:<none>?page=2#top'],
+      ['internal:?page=2#top', [], 'route:<none>?page=2#top'],
     ];
   }
 
   /**
-   * Tests the fromUri() method with a valid user-path: URI.
+   * Tests the fromUri() method with a valid internal: URI.
    *
    * @covers ::fromUri
-   * @dataProvider providerFromValidUserPathUri
+   * @dataProvider providerFromValidInternalUri
    */
-  public function testFromValidUserPathUri($path) {
-    $url = Url::fromUri('user-path:' . $path);
+  public function testFromValidInternalUri($path) {
+    $url = Url::fromUri('internal:' . $path);
     $this->assertInstanceOf('Drupal\Core\Url', $url);
   }
 
   /**
-   * Data provider for testFromValidUserPathUri().
+   * Data provider for testFromValidInternalUri().
    */
-  public function providerFromValidUserPathUri() {
+  public function providerFromValidInternalUri() {
     return [
       // Normal paths with a leading slash.
       ['/kittens'],
@@ -663,6 +707,7 @@ public function providerFromValidUserPathUri() {
       ['/kittens?page=1000'],
       ['/?page=1000'],
       ['?page=1000'],
+      ['?breed=bengal&page=1000'],
       // Paths with various token formats but no leading slash.
       ['/[duckies]'],
       ['/%bunnies'],
@@ -675,20 +720,20 @@ public function providerFromValidUserPathUri() {
   }
 
   /**
-   * Tests the fromUri() method with an invalid user-path: URI.
+   * Tests the fromUri() method with an invalid internal: URI.
    *
    * @covers ::fromUri
    * @expectedException \InvalidArgumentException
-   * @dataProvider providerFromInvalidUserPathUri
+   * @dataProvider providerFromInvalidInternalUri
    */
-  public function testFromInvalidUserPathUri($path) {
-    Url::fromUri('user-path:' . $path);
+  public function testFromInvalidInternalUri($path) {
+    Url::fromUri('internal:' . $path);
   }
 
   /**
-   * Data provider for testFromInvalidUserPathUri().
+   * Data provider for testFromInvalidInternalUri().
    */
-  public function providerFromInvalidUserPathUri() {
+  public function providerFromInvalidInternalUri() {
     return [
       // Normal paths without a leading slash.
       ['kittens'],
@@ -721,7 +766,7 @@ public function testToUriStringForRoute($uri, $options, $uri_string) {
   }
 
   /**
-   * Data provider for testing user-path URIs
+   * Data provider for testing route: URIs.
    */
   public function providerTestToUriStringForRoute() {
     return [
diff --git a/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php b/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php
index e12189f..0e90672 100644
--- a/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php
+++ b/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php
@@ -73,7 +73,7 @@ public function provideTestValidate() {
     $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'entity:node/1', TRUE];
     $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'base:', TRUE];
     $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'base:node', TRUE];
-    $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'user-path:', TRUE];
+    $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'internal:', TRUE];
     $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'public://', FALSE];
     $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'public://foo.png', TRUE];
     $data[] = [$this->getMock('Drupal\Core\TypedData\Type\UriInterface'), 'private://', FALSE];
