diff --git a/core/lib/Drupal/Core/Form/ConfirmFormHelper.php b/core/lib/Drupal/Core/Form/ConfirmFormHelper.php
index b58078d..30e2c8d 100644
--- a/core/lib/Drupal/Core/Form/ConfirmFormHelper.php
+++ b/core/lib/Drupal/Core/Form/ConfirmFormHelper.php
@@ -34,9 +34,7 @@ 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'));
-      // @todo Use Url::fromPath() once https://www.drupal.org/node/2351379 is
-      //   resolved.
-      $url = Url::fromUri('base://' . $options['path'], $options);
+      $url = Url::fromUserEnteredPath($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 999f447..823921b 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -172,6 +172,44 @@ public static function fromRoute($route_name, $route_parameters = array(), $opti
   }
 
   /**
+   * Creates a new Url object for a user-entered path.
+   *
+   * This method should be used for generating URLs where the exact route is
+   * unknown. This should almost never be necessary, except when dealing with
+   * user input, which are paths, or possibly external URLs.
+   *
+   * In general, this method should be avoided except when processing user input
+   * in favor of Url::fromRoute() for Drupal routes, and Url::fromUri() for
+   * external paths, or paths not controlled by Drupal (e.g. text files).
+   *
+   * Note: You can call access() on the returned object to do access checking.
+   *
+   * @param string $path
+   *   The path to be converted. The path may include query arguments and a
+   *   fragment.
+   * @param array $options
+   *   (optional) Additional options used for the url.
+   *
+   * @return \Drupal\Core\Url
+   *   A Url object.
+   *
+   * @see static::fromUri()
+   * @see static::fromRoute()
+   */
+  public static function fromUserEnteredPath($path, array $options = []) {
+    if ($scheme = parse_url($path, PHP_URL_SCHEME)) {
+      $url = static::fromUri($path, $options);
+    }
+    else {
+      $url = \Drupal::pathValidator()
+        ->getUrlIfValidWithoutAccessCheck($path) ?: Url::fromUri('base://' . $path);
+      // Allow to specify additional or override options from the path.
+      $url->setOptions($options + $url->getOptions());
+    }
+    return $url;
+  }
+
+  /**
    * Creates a new URL object from a route match.
    *
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
diff --git a/core/modules/dblog/src/Controller/DbLogController.php b/core/modules/dblog/src/Controller/DbLogController.php
index e8b1ba5..9a838ae 100644
--- a/core/modules/dblog/src/Controller/DbLogController.php
+++ b/core/modules/dblog/src/Controller/DbLogController.php
@@ -255,11 +255,11 @@ public function eventDetails($event_id) {
         ),
         array(
           array('data' => $this->t('Location'), 'header' => TRUE),
-          $this->l($dblog->location, $dblog->location ? Url::fromUri('base://' . $dblog->location) : Url::fromRoute('<none>')),
+          $this->l($dblog->location, $dblog->location ? Url::fromUserEnteredPath($dblog->location) : Url::fromRoute('<none>')),
         ),
         array(
           array('data' => $this->t('Referrer'), 'header' => TRUE),
-          $this->l($dblog->referer, $dblog->referer ? Url::fromUri('base://' . $dblog->referer) : Url::fromRoute('<none>')),
+          $this->l($dblog->referer, $dblog->referer ? Url::fromUserEnteredPath($dblog->location) : Url::fromRoute('<none>')),
         ),
         array(
           array('data' => $this->t('Message'), 'header' => TRUE),
diff --git a/core/modules/field_ui/src/FieldUI.php b/core/modules/field_ui/src/FieldUI.php
index 4bbd93a..1b577ab 100644
--- a/core/modules/field_ui/src/FieldUI.php
+++ b/core/modules/field_ui/src/FieldUI.php
@@ -63,7 +63,7 @@ public static function getNextDestination(array $destinations) {
       // Redirect to any given path within the same domain.
       // @todo Use Url::fromPath() once https://www.drupal.org/node/2351379 is
       //   resolved.
-      $next_destination = Url::fromUri('base://' . $options['path']);
+      $next_destination = Url::fromUserEnteredPath($options['path']);
     }
     return $next_destination;
   }
diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php
index e33e53a..531ff5b 100644
--- a/core/modules/menu_ui/src/Tests/MenuTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuTest.php
@@ -116,7 +116,7 @@ function testMenu() {
     // Verify delete link exists and reset link does not exist.
     $this->drupalGet('admin/structure/menu/manage/' . $this->menu->id());
     $this->assertLinkByHref('admin/structure/menu/item/' . $this->items[0]->id() . '/delete');
-    $this->assertNoLinkByHref(Url::fromUri('base://admin/structure/menu/link/' . $this->items[0]->getPluginId() . '/reset')->toString());
+    $this->assertNoLinkByHref(Url::fromUserEnteredPath('admin/structure/menu/link/' . $this->items[0]->getPluginId() . '/reset')->toString());
     // Check delete and reset access.
     $this->drupalGet('admin/structure/menu/item/' . $this->items[0]->id() . '/delete');
     $this->assertResponse(200);
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 2bb9e62..f5e0e99 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -383,7 +383,6 @@ system.theme_settings_theme:
   options:
     _only_fragment: TRUE
 
-
 '<current>':
   path: '<current>'
 
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 925c84e..f287a19 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
@@ -54,8 +54,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   public function submitForm(array &$form, FormStateInterface $form_state) {
     if (!$form_state->isValueEmpty('redirection')) {
       if (!$form_state->isValueEmpty('destination')) {
-        // @todo Use Url::fromPath() once https://www.drupal.org/node/2351379 is
-        //   resolved.
+        // The destination is a random URL, so we can't use routed URLs.
         $form_state->setRedirectUrl(Url::fromUri('base://' . $form_state->getValue('destination')));
       }
     }
diff --git a/core/modules/views_ui/src/ViewListBuilder.php b/core/modules/views_ui/src/ViewListBuilder.php
index f9ac0e1..29b74b8 100644
--- a/core/modules/views_ui/src/ViewListBuilder.php
+++ b/core/modules/views_ui/src/ViewListBuilder.php
@@ -263,7 +263,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('base://' . $path));
+          // @todo Use the method on the executable when
+          //   https://www.drupal.org/node/2364157 is available.
+          $all_paths[] = \Drupal::l('/' . $path, Url::fromUserEnteredPath($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 e8464fa..0e10ac7 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -702,7 +702,7 @@ public function renderPreview($display_id, $args = array()) {
               Xss::filterAdmin($this->executable->getTitle()),
             );
             if (isset($path)) {
-              $path = \Drupal::l($path, Url::fromUri('base://' . $path));
+              $path = \Drupal::l($path, Url::fromUserEnteredPath($path));
             }
             else {
               $path = t('This display has no path.');
diff --git a/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php b/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php
index b80567f..a96ac58 100644
--- a/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\ConfirmFormHelper;
 use Drupal\Core\Url;
 use Drupal\Tests\UnitTestCase;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -95,8 +96,20 @@ public function testCancelLinkRouteWithUrl() {
   public function testCancelLinkDestination() {
     $query = array('destination' => 'baz');
     $form = $this->getMock('Drupal\Core\Form\ConfirmFormInterface');
+
+    $path_validator = $this->getMock('Drupal\Core\Path\PathValidatorInterface');
+    $container_builder = new ContainerBuilder();
+    $container_builder->set('path.validator', $path_validator);
+    \Drupal::setContainer($container_builder);
+
+    $url = Url::fromRoute('test_route');
+    $path_validator->expects($this->atLeastOnce())
+      ->method('getUrlIfValidWithoutAccessCheck')
+      ->with('baz')
+      ->willReturn($url);
+
     $link = ConfirmFormHelper::buildCancelLink($form, new Request($query));
-    $this->assertSame('base://' . $query['destination'], $link['#url']->getUri());
+    $this->assertSame($url, $link['#url']);
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index cea8770..49d4ca9 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -58,6 +58,13 @@ class UrlTest extends UnitTestCase {
   protected $map;
 
   /**
+   * The mocked path validator.
+   *
+   * @var \Drupal\Core\Path\PathValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $pathValidator;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
@@ -90,10 +97,13 @@ protected function setUp() {
       ->will($this->returnValueMap($alias_map));
 
     $this->router = $this->getMock('Drupal\Tests\Core\Routing\TestRouterInterface');
+    $this->pathValidator = $this->getMock('Drupal\Core\Path\PathValidatorInterface');
+
     $this->container = new ContainerBuilder();
     $this->container->set('router.no_access_checks', $this->router);
     $this->container->set('url_generator', $this->urlGenerator);
     $this->container->set('path.alias_manager', $this->pathAliasManager);
+    $this->container->set('path.validator', $this->pathValidator);
     \Drupal::setContainer($this->container);
   }
 
@@ -160,6 +170,36 @@ public function testFromRouteFront() {
   }
 
   /**
+   * Tests fromUserEnteredPath() method with an invalid route.
+   *
+   * @covers ::fromUserEnteredPath
+   */
+  public function testFromRoutedPathWithInvalidRoute() {
+    $this->pathValidator->expects($this->once())
+      ->method('getUrlIfValidWithoutAccessCheck')
+      ->with('invalid-path')
+      ->willReturn(FALSE);
+    $url = Url::fromUserEnteredPath('invalid-path');
+    $this->assertSame(FALSE, $url->isRouted());
+    $this->assertSame('base://invalid-path', $url->getUri());
+  }
+
+  /**
+   * Tests fromUserEnteredPath() method with a valid route.
+   *
+   * @covers ::fromUserEnteredPath
+   */
+  public function testFromRoutedPathWithValidRoute() {
+    $url = Url::fromRoute('test_route');
+    $this->pathValidator->expects($this->once())
+      ->method('getUrlIfValidWithoutAccessCheck')
+      ->with('valid-path')
+      ->willReturn($url);
+    $result_url = Url::fromUserEnteredPath('valid-path');
+    $this->assertSame($url, $result_url);
+  }
+
+  /**
    * Tests the createFromRequest method.
    *
    * @covers ::createFromRequest
