diff --git a/core/core.services.yml b/core/core.services.yml
index 0d6eb2e..e39252d 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1077,7 +1077,7 @@ services:
       - { name: event_subscriber }
   redirect_response_subscriber:
     class: Drupal\Core\EventSubscriber\RedirectResponseSubscriber
-    arguments: ['@url_generator', '@router.request_context']
+    arguments: ['@unrouted_url_assembler', '@router.request_context']
     tags:
       - { name: event_subscriber }
   redirect_leading_slashes_subscriber:
diff --git a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php
index efaf5c8..09540ea 100644
--- a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php
@@ -11,7 +11,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Routing\LocalRedirectResponse;
 use Drupal\Core\Routing\RequestContext;
-use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
 use Symfony\Component\HttpKernel\KernelEvents;
@@ -25,22 +25,22 @@
 class RedirectResponseSubscriber implements EventSubscriberInterface {
 
   /**
-   * The url generator service.
+   * The unrouted URL assembler service.
    *
-   * @var \Drupal\Core\Routing\UrlGeneratorInterface
+   * @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface
    */
-  protected $urlGenerator;
+  protected $unroutedUrlAssembler;
 
   /**
    * Constructs a RedirectResponseSubscriber object.
    *
-   * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
-   *   The url generator service.
+   * @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface $url_assembler
+   *   The unrouted URL assembler service.
    * @param \Drupal\Core\Routing\RequestContext $request_context
    *   The request context.
    */
-  public function __construct(UrlGeneratorInterface $url_generator, RequestContext $request_context) {
-    $this->urlGenerator = $url_generator;
+  public function __construct(UnroutedUrlAssemblerInterface $url_assembler, RequestContext $request_context) {
+    $this->unroutedUrlAssembler = $url_assembler;
     $this->requestContext = $request_context;
   }
 
@@ -117,19 +117,18 @@ protected function getDestinationAsAbsoluteUrl($destination, $scheme_and_host) {
         $destination = $scheme_and_host . $destination;
       }
       else {
-        // Legacy destination query parameters can be relative paths that have
-        // not yet been converted to URLs (outbound path processors and other
-        // URL handling still needs to be performed).
-        // @todo As generateFromPath() is deprecated, remove this in
-        //   https://www.drupal.org/node/2418219.
+        // Legacy destination query parameters can be internal paths that have
+        // not yet been converted to URLs.
         $destination = UrlHelper::parse($destination);
-        $path = $destination['path'];
+        $uri = 'base:' . $destination['path'];
         $options = [
           'query' => $destination['query'],
           'fragment' => $destination['fragment'],
           'absolute' => TRUE,
         ];
-        $destination = $this->urlGenerator->generateFromPath($path, $options);
+        // Treat this as if it's user input of a path relative to the site's
+        // base URL.
+        $destination = $this->unroutedUrlAssembler->assemble($uri, $options);
       }
     }
     return $destination;
diff --git a/core/lib/Drupal/Core/Menu/menu.api.php b/core/lib/Drupal/Core/Menu/menu.api.php
index defec19..b37fa61 100644
--- a/core/lib/Drupal/Core/Menu/menu.api.php
+++ b/core/lib/Drupal/Core/Menu/menu.api.php
@@ -452,7 +452,7 @@ function hook_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$bread
  *     URL.
  *   - url: The \Drupal\Core\Url object.
  *   - options: An associative array of additional options that will be passed
- *     to either \Drupal\Core\Routing\UrlGenerator::generateFromPath() or
+ *     to either \Drupal\Core\Utility\UnroutedUrlAssembler::assemble() or
  *     \Drupal\Core\Routing\UrlGenerator::generateFromRoute() to generate the
  *     href attribute for this link, and also used when generating the link.
  *     Defaults to an empty array. It may contain the following elements:
@@ -469,7 +469,7 @@ function hook_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$bread
  *       to work as an argument for the constructor of the class
  *       Drupal\Core\Template\Attribute($options['attributes']).
  *
- * @see \Drupal\Core\Routing\UrlGenerator::generateFromPath()
+ * @see \Drupal\Core\Utility\UnroutedUrlAssembler::assemble()
  * @see \Drupal\Core\Routing\UrlGenerator::generateFromRoute()
  */
 function hook_link_alter(&$variables) {
diff --git a/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php b/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php
index b350112..59f2d0c 100644
--- a/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php
+++ b/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php
@@ -22,7 +22,7 @@
    *   The path to process, with a leading slash.
    * @param array $options
    *   An array of options such as would be passed to the generator's
-   *   generateFromPath() method.
+   *   generateFromRoute() method.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The HttpRequest object representing the current request.
    * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata
diff --git a/core/lib/Drupal/Core/Render/MetadataBubblingUrlGenerator.php b/core/lib/Drupal/Core/Render/MetadataBubblingUrlGenerator.php
index 3a4535e..940c0e1 100644
--- a/core/lib/Drupal/Core/Render/MetadataBubblingUrlGenerator.php
+++ b/core/lib/Drupal/Core/Render/MetadataBubblingUrlGenerator.php
@@ -117,17 +117,6 @@ public function generateFromRoute($name, $parameters = array(), $options = array
   /**
    * {@inheritdoc}
    */
-  public function generateFromPath($path = NULL, $options = array(), $collect_bubbleable_metadata = FALSE) {
-    $generated_url = $this->urlGenerator->generateFromPath($path, $options, TRUE);
-    if (!$collect_bubbleable_metadata) {
-      $this->bubble($generated_url, $options);
-    }
-    return $collect_bubbleable_metadata ? $generated_url : $generated_url->getGeneratedUrl();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function supports($name) {
     return $this->urlGenerator->supports($name);
   }
diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php
index d990e40..cf6607a 100644
--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -370,116 +370,6 @@ public function generateFromRoute($name, $parameters = array(), $options = array
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function generateFromPath($path = NULL, $options = array(), $collect_bubbleable_metadata = FALSE) {
-    $generated_url = $collect_bubbleable_metadata ? new GeneratedUrl() : NULL;
-
-    $request = $this->requestStack->getCurrentRequest();
-    $current_base_path = $request->getBasePath() . '/';
-    $current_base_url = $request->getSchemeAndHttpHost() . $current_base_path;
-    $current_script_path = '';
-    $base_path_with_script = $request->getBaseUrl();
-    if (!empty($base_path_with_script)) {
-      $script_name = $request->getScriptName();
-      if (strpos($base_path_with_script, $script_name) !== FALSE) {
-        $current_script_path = ltrim(substr($script_name, strlen($current_base_path)), '/') . '/';
-      }
-    }
-
-    // Merge in defaults.
-    $options += array(
-      'fragment' => '',
-      'query' => array(),
-      'absolute' => FALSE,
-      'prefix' => '',
-    );
-
-    // A duplicate of the code from
-    // \Drupal\Component\Utility\UrlHelper::isExternal() to avoid needing
-    // another function call, since performance inside url() is critical.
-    if (!isset($options['external'])) {
-      $colonpos = strpos($path, ':');
-      // Avoid calling drupal_strip_dangerous_protocols() if there is any slash
-      // (/), hash (#) or question_mark (?) before the colon (:) occurrence -
-      // if any - as this would clearly mean it is not a URL. If the path starts
-      // with 2 slashes then it is always considered an external URL without an
-      // explicit protocol part.
-      $options['external'] = (strpos($path, '//') === 0)
-      || ($colonpos !== FALSE
-        && !preg_match('![/?#]!', substr($path, 0, $colonpos))
-        && UrlHelper::stripDangerousProtocols($path) == $path);
-    }
-
-    if (isset($options['fragment']) && $options['fragment'] !== '') {
-      $options['fragment'] = '#' . $options['fragment'];
-    }
-
-    if ($options['external']) {
-      // Split off the fragment.
-      if (strpos($path, '#') !== FALSE) {
-        list($path, $old_fragment) = explode('#', $path, 2);
-        // If $options contains no fragment, take it over from the path.
-        if (isset($old_fragment) && !$options['fragment']) {
-          $options['fragment'] = '#' . $old_fragment;
-        }
-      }
-      // Append the query.
-      if ($options['query']) {
-        $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($options['query']);
-      }
-      if (isset($options['https'])) {
-        if ($options['https'] === TRUE) {
-          $path = str_replace('http://', 'https://', $path);
-        }
-        elseif ($options['https'] === FALSE) {
-          $path = str_replace('https://', 'http://', $path);
-        }
-      }
-      // Reassemble.
-      $url = $path . $options['fragment'];
-      return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
-    }
-    else {
-      $path = ltrim($this->processPath('/' . $path, $options, $generated_url), '/');
-    }
-
-    if (!isset($options['script'])) {
-      $options['script'] = $current_script_path;
-    }
-    // The base_url might be rewritten from the language rewrite in domain mode.
-    if (!isset($options['base_url'])) {
-      if (isset($options['https'])) {
-        if ($options['https'] === TRUE) {
-          $options['base_url'] = str_replace('http://', 'https://', $current_base_url);
-          $options['absolute'] = TRUE;
-        }
-        elseif ($options['https'] === FALSE) {
-          $options['base_url'] = str_replace('https://', 'http://', $current_base_url);
-          $options['absolute'] = TRUE;
-        }
-      }
-      else {
-        $options['base_url'] = $current_base_url;
-      }
-    }
-    elseif (rtrim($options['base_url'], '/') == $options['base_url']) {
-      $options['base_url'] .= '/';
-    }
-    $base = $options['absolute'] ? $options['base_url'] : $current_base_path;
-    $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix'];
-
-    if ($options['absolute'] && $collect_bubbleable_metadata) {
-      $generated_url->addCacheContexts(['url.site']);
-    }
-
-    $path = str_replace('%2F', '/', rawurlencode($prefix . $path));
-    $query = $options['query'] ? ('?' . UrlHelper::buildQuery($options['query'])) : '';
-    $url = $base . $options['script'] . $path . $query . $options['fragment'];
-    return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
-  }
-
-  /**
    * Passes the path to a processor manager to allow alterations.
    */
   protected function processPath($path, &$options = array(), BubbleableMetadata $bubbleable_metadata = NULL) {
diff --git a/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php b/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
index 97868c3..0db116b 100644
--- a/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
+++ b/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
@@ -17,86 +17,6 @@
 interface UrlGeneratorInterface extends VersatileGeneratorInterface {
 
   /**
-   * Generates an internal or external URL.
-   *
-   * @param string $path
-   *   (optional) The internal path or external URL being linked to, such as
-   *   "node/34" or "http://example.com/foo". The default value is equivalent to
-   *   passing in '<front>'. A few notes:
-   *   - If you provide a full URL, it will be considered an external URL.
-   *   - If you provide only the path (e.g. "node/34"), it will be
-   *     considered an internal link. In this case, it should be a system URL,
-   *     and it will be replaced with the alias, if one exists. Additional query
-   *     arguments for internal paths must be supplied in $options['query'], not
-   *     included in $path.
-   *   - If you provide an internal path and $options['alias'] is set to TRUE, the
-   *     path is assumed already to be the correct path alias, and the alias is
-   *     not looked up.
-   *   - The special string '<front>' generates a link to the site's base URL.
-   *   - If your external URL contains a query (e.g. http://example.com/foo?a=b),
-   *     then you can either URL encode the query keys and values yourself and
-   *     include them in $path, or use $options['query'] to let this method
-   *     URL encode them.
-   *
-   * @param array $options
-   *   (optional) An associative array of additional options, with the following
-   *   elements:
-   *   - 'query': An array of query key/value-pairs (without any URL-encoding) to
-   *     append to the URL.
-   *   - 'fragment': A fragment identifier (named anchor) to append to the URL.
-   *     Do not include the leading '#' character.
-   *   - 'absolute': Defaults to FALSE. Whether to force the output to be an
-   *     absolute link (beginning with http:). Useful for links that will be
-   *     displayed outside the site, such as in an RSS feed.
-   *   - 'alias': Defaults to FALSE. Whether the given path is a URL alias
-   *     already.
-   *   - 'external': Whether the given path is an external URL.
-   *   - 'language': An optional language object. If the path being linked to is
-   *     internal to the site, $options['language'] is used to look up the alias
-   *     for the URL. If $options['language'] is omitted, the language will be
-   *     obtained from
-   *     \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_URL).
-   *   - 'https': Whether this URL should point to a secure location. If not
-   *     defined, the current scheme is used, so the user stays on HTTP or HTTPS
-   *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP.
-   *   - 'base_url': Only used internally by a path processor, for example, to
-   *     modify the base URL when a language dependent URL requires so.
-   *   - 'prefix': Only used internally, to modify the path when a language
-   *     dependent URL requires so.
-   *   - 'script': Added to the URL between the base path and the path prefix.
-   *     Defaults to empty string when clean URLs are in effect, and to
-   *     'index.php/' when they are not.
-   *   - 'entity_type': The entity type of the object that called the URL
-   *     generator. Only set if the URL generator is invoked by
-   *     \Drupal\Core\Entity\Entity::uri().
-   *   - 'entity': The entity object (such as a node) for which the URL is being
-   *     generated. Only set if the URL generator is invoked by
-   *     \Drupal\Core\Entity\Entity::uri().
-   * @param bool $collect_bubbleable_metadata
-   *   (optional) Defaults to FALSE. When TRUE, both the generated URL and its
-   *   associated bubbleable metadata are returned.
-   *
-   * @return string|\Drupal\Core\GeneratedUrl
-   *   A string containing a URL to the given path.
-   *   When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is
-   *   returned, containing the generated URL plus bubbleable metadata.
-   *
-   * @throws \Drupal\Core\Routing\GeneratorNotInitializedException.
-   *
-   * @deprecated in Drupal 8.0.x-dev and will be removed before Drupal 8.0.0.
-   *   To generate URLs for Drupal routes (that is, most pages generated by
-   *   Drupal), see UrlGeneratorInterface::generateFromRoute() instead. For
-   *   non-routed local URIs relative to the base path (like robots.txt) see
-   *   \Drupal\Core\Utility\UnroutedUrlAssembler.
-   *
-   * @see static::generateFromRoute()
-   * @see \Drupal\Core\Utility\UnroutedUrlAssembler
-   * @see \Drupal\Core\Url
-   * @see \Drupal\Core\GeneratedUrl
-   */
-  public function generateFromPath($path = NULL, $options = array(), $collect_bubbleable_metadata = FALSE);
-
-  /**
    * Gets the internal path (system path) of a route.
    *
    * @param string|\Symfony\Component\Routing\Route $name
diff --git a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
index 3c97c44..8179563 100644
--- a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
+++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
@@ -115,11 +115,6 @@ protected function buildLocalUrl($uri, array $options = [], $collect_bubbleable_
     //   https://www.drupal.org/node/2417459
     $uri = substr($uri, 5);
 
-    // Strip leading slashes from internal paths to prevent them becoming
-    // external URLs without protocol. /example.com should not be turned into
-    // //example.com.
-    $uri = ltrim($uri, '/');
-
     // Allow (outbound) path processing, if needed. A valid use case is the path
     // alias overview form:
     // @see \Drupal\path\Controller\PathController::adminOverview().
@@ -128,6 +123,10 @@ protected function buildLocalUrl($uri, array $options = [], $collect_bubbleable_
       // want to include e.g. the request language in the processing.
       $uri = $this->pathProcessor->processOutbound($uri, $options, NULL, $generated_url);
     }
+    // Strip leading slashes from internal paths to prevent them becoming
+    // external URLs without protocol. /example.com should not be turned into
+    // //example.com.
+    $uri = ltrim($uri, '/');
 
     // Add any subdirectory where Drupal is installed.
     $current_base_path = $request->getBasePath() . '/';
@@ -177,8 +176,7 @@ protected function addOptionDefaults(array &$options) {
 
     // If the current request was made with the script name (eg, index.php) in
     // it, then extract it, making sure the leading / is gone, and a trailing /
-    // is added, to allow simple string concatenation with other parts.  This
-    // mirrors code from UrlGenerator::generateFromPath().
+    // is added, to allow simple string concatenation with other parts.
     if (!empty($base_path_with_script)) {
       $script_name = $request->getScriptName();
       if (strpos($base_path_with_script, $script_name) !== FALSE) {
diff --git a/core/modules/action/src/Plugin/Action/GotoAction.php b/core/modules/action/src/Plugin/Action/GotoAction.php
index 770f424..d4c0103 100644
--- a/core/modules/action/src/Plugin/Action/GotoAction.php
+++ b/core/modules/action/src/Plugin/Action/GotoAction.php
@@ -7,12 +7,13 @@
 
 namespace Drupal\action\Plugin\Action;
 
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Action\ConfigurableActionBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -37,11 +38,11 @@ class GotoAction extends ConfigurableActionBase implements ContainerFactoryPlugi
   protected $dispatcher;
 
   /**
-   * The url generator service.
+   * The unrouted URL assembler service.
    *
-   * @var \Drupal\Core\Routing\UrlGeneratorInterface
+   * @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface
    */
-  protected $urlGenerator;
+  protected $unroutedUrlAssembler;
 
   /**
    * Constructs a new DeleteNode object.
@@ -54,29 +55,47 @@ class GotoAction extends ConfigurableActionBase implements ContainerFactoryPlugi
    *   The plugin implementation definition.
    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
    *   The tempstore factory.
-   * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
-   *   The url generator service.
+   * @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface $url_assembler
+   *   The unrouted URL assembler service.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $dispatcher, UrlGeneratorInterface $url_generator) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $dispatcher, UnroutedUrlAssemblerInterface $url_assembler) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->dispatcher = $dispatcher;
-    $this->urlGenerator = $url_generator;
+    $this->unroutedUrlAssembler = $url_assembler;
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static($configuration, $plugin_id, $plugin_definition, $container->get('event_dispatcher'), $container->get('url_generator'));
+    return new static($configuration, $plugin_id, $plugin_definition, $container->get('event_dispatcher'), $container->get('unrouted_url_assembler'));
   }
 
   /**
    * {@inheritdoc}
    */
   public function execute($object = NULL) {
-    $url = $this->urlGenerator
-      ->generateFromPath($this->configuration['url'], array('absolute' => TRUE));
+    $url = $this->configuration['url'];
+    // Leave external URLs unchanged, and assemble others as absolute URLs
+    // relative to the site's base URL.
+    if (!UrlHelper::isExternal($url)) {
+      $parts = UrlHelper::parse($url);
+      // @todo '<front>' is valid input for BC reasons, may be removed by
+      //   https://www.drupal.org/node/2421941
+      if ($parts['path'] === '<front>') {
+        $parts['path'] = '';
+      }
+      $uri = 'base:' . $parts['path'];
+      $options = [
+        'query' => $parts['query'],
+        'fragment' => $parts['fragment'],
+        'absolute' => TRUE,
+      ];
+      // Treat this as if it's user input of a path relative to the site's
+      // base URL.
+      $url = $this->unroutedUrlAssembler->assemble($uri, $options);
+    }
     $response = new RedirectResponse($url);
     $listener = function($event) use ($response) {
       $event->setResponse($response);
@@ -101,7 +120,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
     $form['url'] = array(
       '#type' => 'textfield',
       '#title' => t('URL'),
-      '#description' => t('The URL to which the user should be redirected. This can be an internal URL like node/1234 or an external URL like @url.', array('@url' => 'http://example.com')),
+      '#description' => t('The URL to which the user should be redirected. This can be an internal URL like /node/1234 or an external URL like @url.', array('@url' => 'http://example.com')),
       '#default_value' => $this->configuration['url'],
       '#required' => TRUE,
     );
diff --git a/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php b/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php
index 635ecaa..4904474 100644
--- a/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php
+++ b/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php
@@ -39,13 +39,6 @@ public function generate($name, $parameters = array(), $referenceType = self::AB
   /**
    * {@inheritdoc}
    */
-  public function generateFromPath($path = NULL, $options = array(), $collect_bubbleable_metadata = FALSE) {
-    throw new \Exception();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getPathFromRoute($name, $parameters = array()) {
     throw new \Exception();
   }
diff --git a/core/modules/simpletest/src/BrowserTestBase.php b/core/modules/simpletest/src/BrowserTestBase.php
index e5712c1..385b0af 100644
--- a/core/modules/simpletest/src/BrowserTestBase.php
+++ b/core/modules/simpletest/src/BrowserTestBase.php
@@ -13,6 +13,7 @@
 use Behat\Mink\Mink;
 use Behat\Mink\Session;
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Database\ConnectionNotDefinedException;
 use Drupal\Core\Database\Database;
@@ -23,6 +24,7 @@
 use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\StreamWrapperInterface;
 use Drupal\Core\Test\TestRunnerKernel;
+use Drupal\Core\Url;
 use Drupal\user\UserInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -391,7 +393,7 @@ protected function prepareRequest() {
    * Retrieves a Drupal path or an absolute path.
    *
    * @param string $path
-   *   Drupal path or URL to load into Mink controlled browser.
+   *   Drupal path like /node or URL to load into Mink controlled browser.
    * @param array $options
    *   (optional) Options to be forwarded to the url generator.
    *
@@ -404,7 +406,14 @@ protected function drupalGet($path, array $options = array()) {
     // The URL generator service is not necessarily available yet; e.g., in
     // interactive installer tests.
     if ($this->container->has('url_generator')) {
-      $url = $this->container->get('url_generator')->generateFromPath($path, $options);
+      if (UrlHelper::isExternal($path)) {
+        $url = Url::fromUri($path, $options)->toString();
+      }
+      else {
+        // This is needed for language prefixing.
+        $options['path_processing'] = TRUE;
+        $url = Url::fromUri('base:' . $path, $options)->toString();
+      }
     }
     else {
       $url = $this->getAbsoluteUrl($path);
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index f5c90cf..5b62c50 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -2684,12 +2684,18 @@ protected function drupalGetMails($filter = array()) {
    */
   protected function assertUrl($path, array $options = array(), $message = '', $group = 'Other') {
     if ($path instanceof Url)  {
-      $url = $path->setAbsolute()->toString();
+      $url_obj = $path;
+    }
+    elseif (UrlHelper::isExternal($path)) {
+      $url_obj = Url::fromUri($path, $options);
     }
     else {
-      $options['absolute'] = TRUE;
-      $url = $this->container->get('url_generator')->generateFromPath($path, $options);
+      $uri = $path === '<front>' ? 'base:/' : 'base:/' . $path;
+      // This is needed for language prefixing.
+      $options['path_processing'] = TRUE;
+      $url_obj = Url::fromUri($uri, $options);
     }
+    $url = $url_obj->setAbsolute()->toString();
     if (!$message) {
       $message = SafeMarkup::format('Expected @url matches current URL (@current_url).', array(
         '@url' => var_export($url, TRUE),
@@ -2950,8 +2956,19 @@ protected function buildUrl($path, array $options = array()) {
     // The URL generator service is not necessarily available yet; e.g., in
     // interactive installer tests.
     else if ($this->container->has('url_generator')) {
-      $options['absolute'] = TRUE;
-      return $this->container->get('url_generator')->generateFromPath($path, $options);
+      $force_internal = isset($options['external']) && $options['external'] == FALSE;
+      if (!$force_internal && UrlHelper::isExternal($path)) {
+        return Url::fromUri($path, $options)->toString();
+      }
+      else {
+        $uri = $path === '<front>' ? 'base:/' : 'base:/' . $path;
+        // Path processing is needed for language prefixing.  Skip it when a
+        // path that may look like an external URL is being used as internal.
+        $options['path_processing'] = !$force_internal;
+        return Url::fromUri($uri, $options)
+          ->setAbsolute()
+          ->toString();
+      }
     }
     else {
       return $this->getAbsoluteUrl($path);
diff --git a/core/modules/views/src/Tests/Handler/FieldWebTest.php b/core/modules/views/src/Tests/Handler/FieldWebTest.php
index 3f9a184..ddc9b50 100644
--- a/core/modules/views/src/Tests/Handler/FieldWebTest.php
+++ b/core/modules/views/src/Tests/Handler/FieldWebTest.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Render\RenderContext;
+use Drupal\Core\Url;
 use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
 use Drupal\views\Views;
 
@@ -262,7 +263,7 @@ public function testAlterUrl() {
 
       // @todo The route-based URL generator strips out NULL attributes.
       // $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'fragment' => 'bar', 'absolute' => $absolute]);
-      $expected_result = \Drupal::urlGenerator()->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
+      $expected_result = Url::fromUserInput('/node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute))->toString();
       $alter['path'] = 'node/123?foo#bar';
       $result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
         return $id_field->theme($row);
diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php
index 193c25b..3a0aa79 100644
--- a/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php
+++ b/core/tests/Drupal/Tests/Core/EventSubscriber/RedirectResponseSubscriberTest.php
@@ -8,8 +8,8 @@
 namespace Drupal\Tests\Core\EventSubscriber;
 
 use Drupal\Core\EventSubscriber\RedirectResponseSubscriber;
-use Drupal\Core\Routing\RequestContext;
 use Drupal\Core\Routing\TrustedRedirectResponse;
+use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\DependencyInjection\Container;
 use Symfony\Component\EventDispatcher\EventDispatcher;
@@ -34,6 +34,13 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
   protected $requestContext;
 
   /**
+   * The mocked request context.
+   *
+   * @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $urlAssembler;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
@@ -46,6 +53,17 @@ protected function setUp() {
       ->method('getCompleteBaseUrl')
       ->willReturn('http://example.com/drupal');
 
+    $this->urlAssembler = $this->getMock(UnroutedUrlAssemblerInterface::class);
+    $this->urlAssembler
+      ->expects($this->any())
+      ->method('assemble')
+      ->willReturnMap([
+        ['base:test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/test'],
+        ['base:example.com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example.com'],
+        ['base:example:com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example:com'],
+        ['base:javascript:alert(0)', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/javascript:alert(0)'],
+      ]);
+
     $container = new Container();
     $container->set('router.request_context', $this->requestContext);
     \Drupal::setContainer($container);
@@ -66,27 +84,9 @@ public function testDestinationRedirect(Request $request, $expected) {
     $dispatcher = new EventDispatcher();
     $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
     $response = new RedirectResponse('http://example.com/drupal');
-    $url_generator = $this->getMockBuilder('Drupal\Core\Routing\UrlGenerator')
-      ->disableOriginalConstructor()
-      ->setMethods(array('generateFromPath'))
-      ->getMock();
-
-    if ($expected) {
-      $url_generator
-        ->expects($this->any())
-        ->method('generateFromPath')
-          ->willReturnMap([
-            ['test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/test'],
-            ['example.com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example.com'],
-            ['example:com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example:com'],
-            ['javascript:alert(0)', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/javascript:alert(0)'],
-            ['/test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/test'],
-          ]);
-    }
-
     $request->headers->set('HOST', 'example.com');
 
-    $listener = new RedirectResponseSubscriber($url_generator, $this->requestContext);
+    $listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
     $dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
     $event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
     $dispatcher->dispatch(KernelEvents::RESPONSE, $event);
@@ -127,32 +127,8 @@ public function testDestinationRedirectToExternalUrl($request, $expected) {
     $dispatcher = new EventDispatcher();
     $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
     $response = new RedirectResponse('http://other-example.com');
-    $url_generator = $this->getMockBuilder('Drupal\Core\Routing\UrlGenerator')
-      ->disableOriginalConstructor()
-      ->setMethods(array('generateFromPath'))
-      ->getMock();
 
-    $request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $request_context->expects($this->any())
-      ->method('getCompleteBaseUrl')
-      ->willReturn('http://example.com/drupal');
-
-    if ($expected) {
-      $url_generator
-        ->expects($this->any())
-        ->method('generateFromPath')
-        ->willReturnMap([
-          ['test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/test'],
-          ['example.com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example.com'],
-          ['example:com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example:com'],
-          ['javascript:alert(0)', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/javascript:alert(0)'],
-          ['/test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/test'],
-        ]);
-    }
-
-    $listener = new RedirectResponseSubscriber($url_generator, $request_context);
+    $listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
     $dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
     $event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
     $dispatcher->dispatch(KernelEvents::RESPONSE, $event);
@@ -167,22 +143,10 @@ public function testRedirectWithOptInExternalUrl() {
     $dispatcher = new EventDispatcher();
     $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
     $response = new TrustedRedirectResponse('http://external-url.com');
-    $url_generator = $this->getMockBuilder('Drupal\Core\Routing\UrlGenerator')
-      ->disableOriginalConstructor()
-      ->setMethods(array('generateFromPath'))
-      ->getMock();
-
-    $request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $request_context->expects($this->any())
-      ->method('getCompleteBaseUrl')
-      ->willReturn('http://example.com/drupal');
-
     $request = Request::create('');
     $request->headers->set('HOST', 'example.com');
 
-    $listener = new RedirectResponseSubscriber($url_generator, $request_context);
+    $listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
     $dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
     $event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
     $dispatcher->dispatch(KernelEvents::RESPONSE, $event);
@@ -214,13 +178,8 @@ public function testDestinationRedirectWithInvalidUrl(Request $request) {
     $dispatcher = new EventDispatcher();
     $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
     $response = new RedirectResponse('http://example.com/drupal');
-    $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
-
-    $request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
-      ->disableOriginalConstructor()
-      ->getMock();
 
-    $listener = new RedirectResponseSubscriber($url_generator, $request_context);
+    $listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
     $dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
     $event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
     $dispatcher->dispatch(KernelEvents::RESPONSE, $event);
@@ -257,9 +216,7 @@ public function testSanitizeDestinationForGet($input, $output) {
     $request = new Request();
     $request->query->set('destination', $input);
 
-    $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
-    $request_context = new RequestContext();
-    $listener = new RedirectResponseSubscriber($url_generator, $request_context);
+    $listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
     $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
     $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
 
@@ -283,9 +240,7 @@ public function testSanitizeDestinationForPost($input, $output) {
     $request = new Request();
     $request->request->set('destination', $input);
 
-    $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
-    $request_context = new RequestContext();
-    $listener = new RedirectResponseSubscriber($url_generator, $request_context);
+    $listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
     $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
     $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
 
diff --git a/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php b/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
index 6be8a5a..b4a794e 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
@@ -9,7 +9,9 @@
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Form\FormState;
+use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Url;
+use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
@@ -29,11 +31,19 @@ class FormSubmitterTest extends UnitTestCase {
   protected $urlGenerator;
 
   /**
+   * The mocked unrouted URL assembler.
+   *
+   * @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Utility\UnroutedUrlAssemblerInterface
+   */
+  protected $unroutedUrlAssembler;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
     parent::setUp();
-    $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
+    $this->urlGenerator = $this->getMock(UrlGeneratorInterface::class);
+    $this->unroutedUrlAssembler = $this->getMock(UnroutedUrlAssemblerInterface::class);
   }
 
   /**
@@ -187,9 +197,13 @@ public function testRedirectWithResponseObject() {
   public function testRedirectWithoutResult() {
     $form_submitter = $this->getFormSubmitter();
     $this->urlGenerator->expects($this->never())
-      ->method('generateFromPath');
-    $this->urlGenerator->expects($this->never())
       ->method('generateFromRoute');
+    $this->unroutedUrlAssembler->expects($this->never())
+      ->method('assemble');
+    $container = new ContainerBuilder();
+    $container->set('url_generator', $this->urlGenerator);
+    $container->set('unrouted_url_assembler', $this->unroutedUrlAssembler);
+    \Drupal::setContainer($container);
     $form_state = $this->getMock('Drupal\Core\Form\FormStateInterface');
     $form_state->expects($this->once())
       ->method('getRedirect')
diff --git a/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php b/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
index 6607cb5..4d91218 100644
--- a/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
@@ -349,79 +349,6 @@ public function testUrlGenerationWithHttpsRequirement() {
   }
 
   /**
-   * Tests path-based URL generation.
-   */
-  public function testPathBasedURLGeneration() {
-    $base_path = '/subdir';
-    $base_url = 'http://www.example.com' . $base_path;
-
-    foreach (array('', 'index.php/') as $script_path) {
-      foreach (array(FALSE, TRUE) as $absolute) {
-        // Setup a fake request which looks like a Drupal installed under the
-        // subdir "subdir" on the domain www.example.com.
-        // To reproduce the values install Drupal like that and use a debugger.
-        $server = [
-          'SCRIPT_NAME' => '/subdir/index.php',
-          'SCRIPT_FILENAME' => $this->root . '/index.php',
-          'SERVER_NAME' => 'http://www.example.com',
-        ];
-        $request = Request::create('/subdir/' . $script_path, 'GET', [], [], [], $server);
-        $request->headers->set('host', ['www.example.com']);
-        $this->requestStack->push($request);
-
-        // Determine the expected bubbleable metadata.
-        $expected_cacheability = (new BubbleableMetadata())
-          ->setCacheContexts($absolute ? ['url.site'] : [])
-          ->setCacheMaxAge(Cache::PERMANENT);
-
-        // Get the expected start of the path string.
-        $base = ($absolute ? $base_url . '/' : $base_path . '/') . $script_path;
-        $url = $base . 'node/123';
-        $result = $this->generator->generateFromPath('node/123', array('absolute' => $absolute));
-        $this->assertEquals($url, $result, "$url == $result");
-        $generated_url = $this->generator->generateFromPath('node/123', array('absolute' => $absolute), TRUE);
-        $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
-
-        $url = $base . 'node/123#foo';
-        $result = $this->generator->generateFromPath('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
-        $this->assertEquals($url, $result, "$url == $result");
-        $generated_url = $this->generator->generateFromPath('node/123', array('fragment' => 'foo', 'absolute' => $absolute), TRUE);
-        $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
-
-        $url = $base . 'node/123?foo';
-        $result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
-        $this->assertEquals($url, $result, "$url == $result");
-        $generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute), TRUE);
-        $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
-
-        $url = $base . 'node/123?foo=bar&bar=baz';
-        $result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute));
-        $this->assertEquals($url, $result, "$url == $result");
-        $generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute), TRUE);
-        $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
-
-        $url = $base . 'node/123?foo#bar';
-        $result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
-        $this->assertEquals($url, $result, "$url == $result");
-        $generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute), TRUE);
-        $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
-
-        $url = $base;
-        $result = $this->generator->generateFromPath('<front>', array('absolute' => $absolute));
-        $this->assertEquals($url, $result, "$url == $result");
-        $generated_url = $this->generator->generateFromPath('<front>', array('absolute' => $absolute), TRUE);
-        $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
-      }
-    }
-  }
-
-  /**
    * Tests generating a relative URL with no path.
    *
    * @param array $options
