diff --git a/core/core.services.yml b/core/core.services.yml
index 6954b56d88b16cfe75af66ec39679af5a057503e..b605968d6c382ed3a16941bf2eaed923ee906a29 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -566,7 +566,7 @@ services:
       - { name: backend_overridable }
   path.matcher:
     class: Drupal\Core\Path\PathMatcher
-    arguments: ['@config.factory']
+    arguments: ['@config.factory', '@current_route_match']
   path.validator:
     class: Drupal\Core\Path\PathValidator
     arguments: ['@router', '@router.no_access_checks', '@current_user', '@path_processor_manager']
diff --git a/core/includes/batch.inc b/core/includes/batch.inc
index 088889dc3eabe8a9bd7e11417d0c658ff7d79635..a38e00bdeaf05cf49b2885bd97ace342776c9a42 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -450,18 +450,20 @@ function _batch_finished() {
     }
     if ($_batch['form_state']->getRedirect() === NULL) {
       $redirect = $_batch['batch_redirect'] ?: $_batch['source_url'];
-      $options = UrlHelper::parse($redirect);
       // Any path with a scheme does not correspond to a route.
-      if (parse_url($options['path'], PHP_URL_SCHEME)) {
-        $redirect = Url::fromUri($options['path'], $options);
-      }
-      else {
-        $redirect = \Drupal::pathValidator()->getUrlIfValid($options['path']);
-        if (!$redirect) {
-          // Stay on the same page if the redirect was invalid.
-          $redirect = Url::fromRoute('<current>');
+      if (!$redirect instanceof Url) {
+        $options = UrlHelper::parse($redirect);
+        if (parse_url($options['path'], PHP_URL_SCHEME)) {
+          $redirect = Url::fromUri($options['path'], $options);
+        }
+        else {
+          $redirect = \Drupal::pathValidator()->getUrlIfValid($options['path']);
+          if (!$redirect) {
+            // Stay on the same page if the redirect was invalid.
+            $redirect = Url::fromRoute('<current>');
+          }
+          $redirect->setOptions($options);
         }
-        $redirect->setOptions($options);
       }
       $_batch['form_state']->setRedirectUrl($redirect);
     }
@@ -480,16 +482,17 @@ function _batch_finished() {
       $_SESSION['batch_form_state'] = $_batch['form_state'];
     }
     $callback = $_batch['redirect_callback'];
+    /** @var \Drupal\Core\Url $source_url */
+    $source_url = $_batch['source_url'];
     if (is_callable($callback)) {
       $callback($_batch['source_url'], array('query' => array('op' => 'finish', 'id' => $_batch['id'])));
     }
     elseif ($callback === NULL) {
       // Default to RedirectResponse objects when nothing specified.
-      $url = _url($_batch['source_url'], array(
-        'absolute' => TRUE,
-        'query' => array('op' => 'finish', 'id' => $_batch['id']),
-      ));
-      return new RedirectResponse($url);
+      $url = $source_url
+        ->setAbsolute()
+        ->setOption('query', ['op' => 'finish', 'id' => $_batch['id']]);
+      return new RedirectResponse($url->toString());
     }
   }
 }
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 43d7368b9f2d2379c01956cb4a04efbeb1101264..1cd178c9e1f5576e5ea4ae605d3e15ccc536e109 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1132,8 +1132,6 @@ function language_default() {
  *
  * @return
  *   The requested Drupal URL path.
- *
- * @see current_path()
  */
 function request_path() {
   static $path;
@@ -1168,18 +1166,6 @@ function request_path() {
   return $path;
 }
 
-/**
- * @todo This is a temporary function pending refactoring Drupal to use
- *   Symfony's Request object exclusively.
- */
-function _current_path($path = NULL) {
-  static $current_path = '';
-  if (isset($path)) {
-    $current_path = $path;
-  }
-  return $current_path;
-}
-
 /**
  * Registers an additional namespace.
  *
diff --git a/core/includes/common.inc b/core/includes/common.inc
index e7d19edb25eea42e82b225dcad99fef078ed2520..f58fc1b0abd674fc776f44cfe751a50b3fbfad8e 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -23,6 +23,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpFoundation\Request;
 use Drupal\Core\PhpStorage\PhpStorageFactory;
@@ -245,7 +246,6 @@ function drupal_get_html_head($render = TRUE) {
  *   - destination: The path provided via the destination query string or, if
  *     not available, the current path.
  *
- * @see current_path()
  * @ingroup form_api
  */
 function drupal_get_destination() {
@@ -260,7 +260,7 @@ function drupal_get_destination() {
     $destination = array('destination' => $query->get('destination'));
   }
   else {
-    $path = current_path();
+    $path = \Drupal::routeMatch()->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath() : '';
     $query = UrlHelper::buildQuery(UrlHelper::filterQueryParameters($query->all()));
     if ($query != '') {
       $path .= '?' . $query;
@@ -1469,18 +1469,20 @@ function _drupal_add_js($data = NULL, $options = NULL) {
           // Instead of running the hook_url_outbound_alter() again here, extract
           // them from url().
           // @todo Make this less hacky: http://drupal.org/node/1547376.
-          $scriptPath = $GLOBALS['script_path'];
+          $request = \Drupal::request();
+          $scriptPath = $request->getScriptName();
+
           $pathPrefix = '';
-          $current_query = \Drupal::service('request_stack')->getCurrentRequest()->query->all();
+          $current_query = $request->query->all();
           _url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix));
-          $current_path = current_path();
+          $current_path = \Drupal::routeMatch()->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath() : '';
           $current_path_is_admin = FALSE;
           // The function path_is_admin() is not available on update.php pages.
           if (!(defined('MAINTENANCE_MODE'))) {
             $current_path_is_admin = \Drupal::service('router.admin_context')->isAdminRoute();
           }
           $path = array(
-            'basePath' => base_path(),
+            'baseUrl' => $request->getBaseUrl() . '/',
             'scriptPath' => $scriptPath,
             'pathPrefix' => $pathPrefix,
             'currentPath' => $current_path,
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 075e37b6e88fc5182c9ab921563231576d56b0de..1452a6300fad31c8cec8040a4c3cb1b142baf025 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -15,6 +15,7 @@
 use Drupal\Core\Form\OptGroup;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
@@ -827,7 +828,7 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NU
       'progressive' => TRUE,
       'url' => $url,
       'url_options' => array(),
-      'source_url' => current_path(),
+      'source_url' => Url::fromRouteMatch(\Drupal::routeMatch()),
       'batch_redirect' => $redirect,
       'theme' => \Drupal::theme()->getActiveTheme()->getName(),
       'redirect_callback' => $redirect_callback,
diff --git a/core/includes/path.inc b/core/includes/path.inc
index b0cc2fea51a0e9ebdd9ede37ec44caf46a8bb10b..64f020c38bcb171fce55f33e9482e3cfe8825f0d 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -39,36 +39,6 @@ function drupal_match_path($path, $patterns) {
   return \Drupal::service('path.matcher')->matchPath($path, $patterns);
 }
 
-/**
- * Return the current URL path of the page being viewed.
- *
- * Examples:
- * - http://example.com/node/306 returns "node/306".
- * - http://example.com/drupalfolder/node/306 returns "node/306" while
- *   base_path() returns "/drupalfolder/".
- * - http://example.com/path/alias (which is a path alias for node/306) returns
- *   "node/306" as opposed to the path alias.
- *
- * @return string
- *   The current Drupal URL path.
- *
- * @see request_path()
- */
-function current_path() {
-  // @todo Remove the check for whether the request service exists and the
-  // fallback code below, once the path alias logic has been figured out in
-  // http://drupal.org/node/1269742.
-  if ($request = \Drupal::request()) {
-    $path = $request->attributes->get('_system_path');
-    if ($path !== NULL) {
-      return $path;
-    }
-  }
-  // If we are outside the request scope, fall back to using the path stored in
-  // _current_path().
-  return _current_path();
-}
-
 /**
  * Determines whether a path is in the administrative section of the site.
  *
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index dc40e4fd81f8992db17597251a6d52475979c223..2c58ccc7035fed02a2ffc7d0ab47b85456c1c81d 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -22,6 +22,7 @@
 use Drupal\Core\PageCache\RequestPolicyInterface;
 use Drupal\Core\PhpStorage\PhpStorageFactory;
 use Drupal\Core\Site\Settings;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
 use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
@@ -32,6 +33,7 @@
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 use Symfony\Component\HttpKernel\TerminableInterface;
 use Composer\Autoload\ClassLoader;
+use Symfony\Component\Routing\Route;
 
 /**
  * The DrupalKernel class is the core of Drupal itself.
@@ -585,6 +587,8 @@ public function prepareLegacyRequest(Request $request) {
     $this->preHandle($request);
     // Enter the request scope so that current_user service is available for
     // locale/translation sake.
+    $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('<none>'));
+    $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<none>');
     $this->container->get('request_stack')->push($request);
     $this->container->get('router.request_context')->fromRequest($request);
     return $this;
@@ -809,8 +813,6 @@ protected function initializeRequestGlobals(Request $request) {
     global $base_secure_url, $base_insecure_url;
 
     // @todo Refactor with the Symfony Request object.
-    _current_path(request_path());
-
     if (isset($base_url)) {
       // Parse fixed base URL from settings.php.
       $parts = parse_url($base_url);
diff --git a/core/lib/Drupal/Core/Path/PathMatcher.php b/core/lib/Drupal/Core/Path/PathMatcher.php
index 95c56dded8b2065cf49859d4125ffb40ada1534b..a7eed138161bf79101528ce5a9894626c0afa714 100644
--- a/core/lib/Drupal/Core/Path/PathMatcher.php
+++ b/core/lib/Drupal/Core/Path/PathMatcher.php
@@ -8,6 +8,8 @@
 namespace Drupal\Core\Path;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Url;
 
 /**
  * Provides a path matcher.
@@ -42,14 +44,24 @@ class PathMatcher implements PathMatcherInterface {
    */
   protected $configFactory;
 
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
   /**
    * Creates a new PathMatcher.
    *
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The config factory.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    */
-  public function __construct(ConfigFactoryInterface $config_factory) {
+  public function __construct(ConfigFactoryInterface $config_factory, RouteMatchInterface $route_match) {
     $this->configFactory = $config_factory;
+    $this->routeMatch = $route_match;
   }
 
   /**
@@ -84,7 +96,13 @@ public function matchPath($path, $patterns) {
   public function isFrontPage() {
     // Cache the result as this is called often.
     if (!isset($this->isCurrentFrontPage)) {
-      $this->isCurrentFrontPage = (current_path() == $this->getFrontPagePath());
+      $this->isCurrentFrontPage = FALSE;
+      // Ensure that the code can also be executed when there is no active
+      // route match, like on exception responses.
+      if ($this->routeMatch->getRouteName()) {
+        $url = Url::fromRouteMatch($this->routeMatch);
+        $this->isCurrentFrontPage = ($url->getRouteName() && $url->getInternalPath() === $this->getFrontPagePath());
+      }
     }
     return $this->isCurrentFrontPage;
   }
@@ -98,6 +116,8 @@ public function isFrontPage() {
   protected function getFrontPagePath() {
     // Lazy-load front page config.
     if (!isset($this->frontPage)) {
+      // @todo page.front should store the route name, see
+      //   https://www.drupal.org/node/2371823
       $this->frontPage = $this->configFactory->get('system.site')
         ->get('page.front');
     }
diff --git a/core/lib/Drupal/Core/Render/Element/RenderElement.php b/core/lib/Drupal/Core/Render/Element/RenderElement.php
index d9888c0c435c60f18fba594cf891afadc50aa2d0..bd30b47a3d1cbe594665ce5b55289e0fd20646c5 100644
--- a/core/lib/Drupal/Core/Render/Element/RenderElement.php
+++ b/core/lib/Drupal/Core/Render/Element/RenderElement.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Url;
 
 /**
  * Provides a base class for render element plugins.
@@ -136,7 +137,7 @@ public static function processAjaxForm(&$element, FormStateInterface $form_state
   /**
    * Adds Ajax information about an element to communicate with JavaScript.
    *
-   * If #ajax['path'] is set on an element, this additional JavaScript is added
+   * If #ajax['url'] is set on an element, this additional JavaScript is added
    * to the page header to attach the Ajax behaviors. See ajax.js for more
    * information.
    *
@@ -145,7 +146,7 @@ public static function processAjaxForm(&$element, FormStateInterface $form_state
    *   Properties used:
    *   - #ajax['event']
    *   - #ajax['prevent']
-   *   - #ajax['path']
+   *   - #ajax['url']
    *   - #ajax['options']
    *   - #ajax['wrapper']
    *   - #ajax['parameters']
@@ -248,8 +249,13 @@ public static function preRenderAjaxForm($element) {
       }
 
       // Change path to URL.
-      $settings['url'] = isset($settings['path']) ? _url($settings['path'], $settings['options']) : NULL;
-      unset($settings['path'], $settings['options']);
+      if (isset($settings['url']) && $settings['url'] instanceof Url) {
+        $settings['url'] = $settings['url']->setOptions($settings['options'])->toString();
+      }
+      else {
+        $settings['url'] = NULL;
+      }
+      unset($settings['options']);
 
       // Add special data to $settings['submit'] so that when this element
       // triggers an Ajax submission, Drupal's form processing can determine which
diff --git a/core/lib/Drupal/Core/Routing/NullGenerator.php b/core/lib/Drupal/Core/Routing/NullGenerator.php
index 6ec6e118568a86a04e3a34807f3ab2ed4ff55f93..f78ce63313d187813643e8c5117cf9bf1ad5e088 100644
--- a/core/lib/Drupal/Core/Routing/NullGenerator.php
+++ b/core/lib/Drupal/Core/Routing/NullGenerator.php
@@ -38,6 +38,12 @@ protected function getRoute($name) {
     if ($name === '<front>') {
       return new Route('/');
     }
+    elseif ($name === '<current>') {
+      return new Route($this->requestStack->getCurrentRequest()->getPathInfo());
+    }
+    elseif ($name === '<none>') {
+      return new Route('');
+    }
     throw new RouteNotFoundException();
   }
 
diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index 9ea38b213539f6438f5df8e5ba1ce141d809641e..39ce1251b3db32e0db233d25509d6abc227eeb92 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
@@ -86,6 +87,13 @@ class Url {
    */
   protected $uri;
 
+  /**
+   * Stores the internal path, if already requested by getInternalPath
+   *
+   * @var string
+   */
+  protected $internalPath;
+
   /**
    * Constructs a new Url object.
    *
@@ -165,6 +173,23 @@ public static function fromRoute($route_name, $route_parameters = array(), $opti
     return new static($route_name, $route_parameters, $options);
   }
 
+  /**
+   * Creates a new URL object from a route match.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
+   *
+   * @return $this
+   */
+  public static function fromRouteMatch(RouteMatchInterface $route_match) {
+    if ($route_match->getRouteObject()) {
+      return new static($route_match->getRouteName(), $route_match->getRawParameters()->all());
+    }
+    else {
+      throw new \InvalidArgumentException('Route required');
+    }
+  }
+
   /**
    * Creates a new Url object for a URI that does not have a Drupal route.
    *
@@ -510,7 +535,11 @@ public function getInternalPath() {
     if ($this->unrouted) {
       throw new \UnexpectedValueException('Unrouted URIs do not have internal representations.');
     }
-    return $this->urlGenerator()->getPathFromRoute($this->getRouteName(), $this->getRouteParameters());
+
+    if (!isset($this->internalPath)) {
+      $this->internalPath = $this->urlGenerator()->getPathFromRoute($this->getRouteName(), $this->getRouteParameters());
+    }
+    return $this->internalPath;
   }
 
   /**
@@ -582,12 +611,13 @@ protected function unroutedUrlAssembler() {
    * Sets the URL generator.
    *
    * @param \Drupal\Core\Routing\UrlGeneratorInterface
-   *   The URL generator.
+   *   (optional) The URL generator, specify NULL to reset it.
    *
    * @return $this
    */
-  public function setUrlGenerator(UrlGeneratorInterface $url_generator) {
+  public function setUrlGenerator(UrlGeneratorInterface $url_generator = NULL) {
     $this->urlGenerator = $url_generator;
+    $this->internalPath = NULL;
     return $this;
   }
 
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index c432706c83afe745f0eeec9f23b8b3e922926f47..82d60449b5c0bffd9ae15d38a84e18a773ee27da 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -9,7 +9,7 @@
    * page. The request returns an array of commands encoded in JSON, which is
    * then executed to make any changes that are necessary to the page.
    *
-   * Drupal uses this file to enhance form elements with #ajax['path'] and
+   * Drupal uses this file to enhance form elements with #ajax['url'] and
    * #ajax['wrapper'] properties. If set, this file will automatically be included
    * to provide Ajax capabilities.
    */
diff --git a/core/misc/drupal.js b/core/misc/drupal.js
index ce1399499ff999203e85bf3b60db4176f6c84945..dcfad008e90a2b34fe90c83efe6f79309ee3b6a7 100644
--- a/core/misc/drupal.js
+++ b/core/misc/drupal.js
@@ -326,7 +326,7 @@ if (window.jQuery) {
    * Returns the URL to a Drupal page.
    */
   Drupal.url = function (path) {
-    return drupalSettings.path.basePath + drupalSettings.path.scriptPath + drupalSettings.path.pathPrefix + path;
+    return drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + path;
   };
 
   /**
diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js
index 7ec93f592c260837fe661ea837b4ae94fb5c9021..02819ac4f6c4a340c72234d43c73605875a82717 100644
--- a/core/misc/machine-name.js
+++ b/core/misc/machine-name.js
@@ -173,7 +173,7 @@
      *   The transliterated source string.
      */
     transliterate: function (source, settings) {
-      return $.get(drupalSettings.path.basePath + 'machine_name/transliterate', {
+      return $.get(Drupal.url('machine_name/transliterate'), {
         text: source,
         langcode: drupalSettings.langcode,
         replace_pattern: settings.replace_pattern,
diff --git a/core/modules/field/src/Plugin/views/field/Field.php b/core/modules/field/src/Plugin/views/field/Field.php
index 1f781540632ce976835dcb86cd8a5404432c69ce..95dd59e12a977419df0098d760d8b5901bfa6e66 100644
--- a/core/modules/field/src/Plugin/views/field/Field.php
+++ b/core/modules/field/src/Plugin/views/field/Field.php
@@ -469,7 +469,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       '#options' => $formatters,
       '#default_value' => $this->options['type'],
       '#ajax' => array(
-        'path' => views_ui_build_form_path($form_state),
+        'url' => views_ui_build_form_url($form_state),
       ),
       '#submit' => array(array($this, 'submitTemporaryForm')),
       '#executes_submit_callback' => TRUE,
diff --git a/core/modules/file/src/Element/ManagedFile.php b/core/modules/file/src/Element/ManagedFile.php
index 7a9e05f17a50ba1e48b86a7884f23a1487119fd3..34c20e8cc9215909d2427ee71545ab5f9a7beb01 100644
--- a/core/modules/file/src/Element/ManagedFile.php
+++ b/core/modules/file/src/Element/ManagedFile.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element\FormElement;
+use Drupal\Core\Url;
 use Drupal\file\Entity\File;
 
 /**
@@ -144,7 +145,7 @@ public static function processManagedFile(&$element, FormStateInterface $form_st
     $element['#tree'] = TRUE;
 
     $ajax_settings = [
-      'path' => 'file/ajax',
+      'url' => Url::fromRoute('file.ajax_upload'),
       'options' => [
         'query' => [
           'element_parents' => implode('/', $element['#array_parents']),
@@ -219,7 +220,7 @@ public static function processManagedFile(&$element, FormStateInterface $form_st
       }
 
       // Add the upload progress callback.
-      $element['upload_button']['#ajax']['progress']['path'] = 'file/progress/' . $upload_progress_key;
+      $element['upload_button']['#ajax']['progress']['url'] = Url::fromRoute('file.ajax_progress');
     }
 
     // The file upload field itself.
diff --git a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
index ab0c6a89fb44287ac339a672fa81383ecf3c0a64..d5a3e3d52c6ab0c3497f94cee8829e77ed6cddab 100644
--- a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
+++ b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\file\Element\ManagedFile;
+use Drupal\Core\Url;
 
 /**
  * Plugin implementation of the 'file_generic' widget.
@@ -381,7 +382,7 @@ public static function process($element, FormStateInterface $form_state, $form)
     // file, the entire group of file fields is updated together.
     if ($element['#cardinality'] != 1) {
       $parents = array_slice($element['#array_parents'], 0, -1);
-      $new_path = 'file/ajax';
+      $new_url = Url::fromRoute('file.ajax_upload');
       $new_options = array(
         'query' => array(
           'element_parents' => implode('/', $parents),
@@ -392,7 +393,7 @@ public static function process($element, FormStateInterface $form_state, $form)
       $new_wrapper = $field_element['#id'] . '-ajax-wrapper';
       foreach (Element::children($element) as $key) {
         if (isset($element[$key]['#ajax'])) {
-          $element[$key]['#ajax']['path'] = $new_path;
+          $element[$key]['#ajax']['url'] = $new_url->setOptions($new_options);
           $element[$key]['#ajax']['options'] = $new_options;
           $element[$key]['#ajax']['wrapper'] = $new_wrapper;
         }
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index db9888263daa00547b68d13992d4f0b43a48b1a3..cb67d4e307b26aac1f814a199c678adb3452ecc6 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -297,7 +297,7 @@ function shortcut_preprocess_page(&$variables) {
   // we do not want to display it on "access denied" or "page not found"
   // pages).
   if (shortcut_set_edit_access()->isAllowed() && !\Drupal::request()->attributes->has('exception')) {
-    $link = current_path();
+    $link = Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath();
     $route_match = \Drupal::routeMatch();
 
     $query = array(
diff --git a/core/modules/simpletest/src/InstallerTestBase.php b/core/modules/simpletest/src/InstallerTestBase.php
index 92af365291a399a83b7de9a3b42e89759694d3e8..206507519ea5b19fe1660d6e881837cdc2ac7cec 100644
--- a/core/modules/simpletest/src/InstallerTestBase.php
+++ b/core/modules/simpletest/src/InstallerTestBase.php
@@ -164,13 +164,6 @@ protected function setUp() {
       ->set('interface.default', 'test_mail_collector')
       ->save();
 
-    // When running from run-tests.sh we don't get an empty current path which
-    // would indicate we're on the home page.
-    $path = current_path();
-    if (empty($path)) {
-      _current_path('run-tests');
-    }
-
     $this->isInstalled = TRUE;
   }
 
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 9350dfa12dfd9245892aa65a51473a531813872c..93a5047f1a89039fefffc6151c9b51e3de3b0003 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -932,12 +932,6 @@ protected function setUp() {
     //   DrupalKernel::prepareLegacyRequest() -> DrupalKernel::boot() but that
     //   appears to be calling a different container.
     $this->container->get('stream_wrapper_manager')->register();
-    // Temporary fix so that when running from run-tests.sh we don't get an
-    // empty current path which would indicate we're on the home page.
-    $path = current_path();
-    if (empty($path)) {
-      _current_path('run-tests');
-    }
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Common/JavaScriptTest.php b/core/modules/system/src/Tests/Common/JavaScriptTest.php
index a8a4874250d586b6380d3ffe1b00ccd30b3fa41c..2196de6dc0c1d417d5dfcbb367cb0ef39691d345 100644
--- a/core/modules/system/src/Tests/Common/JavaScriptTest.php
+++ b/core/modules/system/src/Tests/Common/JavaScriptTest.php
@@ -42,6 +42,9 @@ protected function setUp() {
 
     // Reset _drupal_add_js() statics before each test.
     drupal_static_reset('_drupal_add_js');
+
+    $this->installSchema('system', 'router');
+    \Drupal::service('router.builder')->rebuild();
   }
 
   protected function tearDown() {
@@ -156,7 +159,7 @@ function testHeaderSetting() {
     $this->render($attached);
 
     $javascript = drupal_get_js('header');
-    $this->assertTrue(strpos($javascript, 'basePath') > 0, 'Rendered JavaScript header returns basePath setting.');
+    $this->assertTrue(strpos($javascript, 'baseUrl') > 0, 'Rendered JavaScript header returns baseUrl setting.');
     $this->assertTrue(strpos($javascript, 'scriptPath') > 0, 'Rendered JavaScript header returns scriptPath setting.');
     $this->assertTrue(strpos($javascript, 'pathPrefix') > 0, 'Rendered JavaScript header returns pathPrefix setting.');
     $this->assertTrue(strpos($javascript, 'currentPath') > 0, 'Rendered JavaScript header returns currentPath setting.');
diff --git a/core/modules/system/src/Tests/Common/PageRenderTest.php b/core/modules/system/src/Tests/Common/PageRenderTest.php
index e9eb691b536c6b8d1d7943a60f6b98516e27455b..b879f3733dec50e98e3f0acaca9c75fcdb239fe0 100644
--- a/core/modules/system/src/Tests/Common/PageRenderTest.php
+++ b/core/modules/system/src/Tests/Common/PageRenderTest.php
@@ -21,7 +21,10 @@ class PageRenderTest extends KernelTestBase {
    * Tests hook_page_attachments() exceptions.
    */
   function testHookPageAttachmentsExceptions() {
-    $this->enableModules(['common_test']);
+    $this->enableModules(['common_test', 'system']);
+    $this->installSchema('system', 'router');
+    \Drupal::service('router.builder')->rebuild();
+
     $this->assertPageRenderHookExceptions('common_test', 'hook_page_attachments');
   }
 
@@ -29,7 +32,10 @@ function testHookPageAttachmentsExceptions() {
    * Tests hook_page_attachments_alter() exceptions.
    */
   function testHookPageAlter() {
-    $this->enableModules(['common_test']);
+    $this->enableModules(['common_test', 'system']);
+    $this->installSchema('system', 'router');
+    \Drupal::service('router.builder')->rebuild();
+
     $this->assertPageRenderHookExceptions('common_test', 'hook_page_attachments_alter');
   }
 
diff --git a/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php b/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php
index 7f64ddb958db0623985d51fac44acee351fa9c76..56728c1e521c1636806486a59ca89597917c5baf 100644
--- a/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php
+++ b/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php
@@ -74,15 +74,6 @@ function testUrlAlter() {
     $this->assertUrlOutboundAlter("forum/" . $term->id(), "community/" . $term->id());
   }
 
-  /**
-   * Test current_path() and request_path().
-   */
-  function testCurrentUrlRequestedPath() {
-    $this->drupalGet('url-alter-test/bar');
-    $this->assertRaw('request_path=url-alter-test/bar', 'request_path() returns the requested path.');
-    $this->assertRaw('current_path=url-alter-test/foo', 'current_path() returns the internal path.');
-  }
-
   /**
    * Assert that an outbound path is altered to an expected value.
    *
diff --git a/core/modules/system/src/Tests/Theme/TableTest.php b/core/modules/system/src/Tests/Theme/TableTest.php
index b781d20d6f2b9935789def7c42763e153a86f3cd..5e83c9109bffcf612d2c152d7cf7f63d5ec92e7d 100644
--- a/core/modules/system/src/Tests/Theme/TableTest.php
+++ b/core/modules/system/src/Tests/Theme/TableTest.php
@@ -23,6 +23,16 @@ class TableTest extends DrupalUnitTestBase {
    */
   public static $modules = array('system');
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', 'router');
+    \Drupal::service('router.builder')->rebuild();
+  }
+
   /**
    * Tableheader.js provides 'sticky' table headers, and is included by default.
    */
diff --git a/core/modules/system/src/Tests/Theme/ThemeTest.php b/core/modules/system/src/Tests/Theme/ThemeTest.php
index 7f3587fa371e1efb693112bee4055f3e6da7c0c9..ed46e534255cc49c9572c81edd06e616437d7026 100644
--- a/core/modules/system/src/Tests/Theme/ThemeTest.php
+++ b/core/modules/system/src/Tests/Theme/ThemeTest.php
@@ -10,6 +10,9 @@
 use Drupal\Component\Serialization\Json;
 use Drupal\simpletest\WebTestBase;
 use Drupal\test_theme\ThemeClass;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
 
 /**
  * Tests low-level theme functions.
@@ -137,14 +140,16 @@ public function testThemeOnNonHtmlRequest() {
    * Ensure page-front template suggestion is added when on front page.
    */
   function testFrontPageThemeSuggestion() {
-    $original_path = _current_path();
-    // Set the current path to node because theme_get_suggestions() will query
-    // it to see if we are on the front page.
-    \Drupal::config('system.site')->set('page.front', 'node')->save();
-    _current_path('node');
-    $suggestions = theme_get_suggestions(array('node'), 'page');
+    // Set the current route to user.login because theme_get_suggestions() will
+    // query it to see if we are on the front page.
+    $request = Request::create('/user/login');
+    $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'user.login');
+    $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/user/login'));
+    \Drupal::requestStack()->push($request);
+    \Drupal::config('system.site')->set('page.front', 'user/login')->save();
+    $suggestions = theme_get_suggestions(array('user', 'login'), 'page');
     // Set it back to not annoy the batch runner.
-    _current_path($original_path);
+    \Drupal::requestStack()->pop();
     $this->assertTrue(in_array('page__front', $suggestions), 'Front page template was suggested.');
   }
 
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 32193beedecb3845dcdea2411cdbce05e7510624..17e88f393dadda23357d355e5377d4dc08fcab12 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -237,7 +237,12 @@ function system_hook_info() {
  * Implements hook_theme_suggestions_HOOK().
  */
 function system_theme_suggestions_html(array $variables) {
-  $path_args = explode('/', current_path());
+  if (\Drupal::service('path.matcher')->isFrontPage()) {
+    $path_args = [''];
+  }
+  else {
+    $path_args = explode('/', Url::fromRoute('<current>')->getInternalPath());
+  }
   return theme_get_suggestions($path_args, 'html');
 }
 
@@ -245,7 +250,12 @@ function system_theme_suggestions_html(array $variables) {
  * Implements hook_theme_suggestions_HOOK().
  */
 function system_theme_suggestions_page(array $variables) {
-  $path_args = explode('/', current_path());
+  if (\Drupal::service('path.matcher')->isFrontPage()) {
+    $path_args = [''];
+  }
+  else {
+    $path_args = explode('/', Url::fromRoute('<current>')->getInternalPath());
+  }
   return theme_get_suggestions($path_args, 'page');
 }
 
@@ -612,7 +622,7 @@ function system_page_attachments(array &$page) {
     $page['#post_render_cache']['\Drupal\system\Controller\SystemController::setLinkActiveClass'] = array(
       // Collect the current state that determines whether a link is active.
       array(
-        'path' => current_path(),
+        'path' => \Drupal::routeMatch()->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath() : '',
         'front' => drupal_is_front_page(),
         'language' => \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(),
         'query' => \Drupal::request()->query->all(),
diff --git a/core/modules/system/tests/modules/url_alter_test/src/Controller/URLAlterTestController.php b/core/modules/system/tests/modules/url_alter_test/src/Controller/URLAlterTestController.php
deleted file mode 100644
index da062223341d8b3510438d05b9b73e1775a9e1c2..0000000000000000000000000000000000000000
--- a/core/modules/system/tests/modules/url_alter_test/src/Controller/URLAlterTestController.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-/**
- * @file
- * Contains \Drupal\url_alter_test\Controller\URLAlterTestController.
- */
-
-namespace Drupal\url_alter_test\Controller;
-
-use Symfony\Component\HttpFoundation\Response;
-
-/**
- * Controller routines for url_alter_test routes.
- */
-class URLAlterTestController {
-
-  /**
-   * Prints Current and Request Path.
-   *
-   * @return \Symfony\Component\HttpFoundation\Response
-   *   A response object.
-   */
-  public function foo() {
-    return new Response('current_path=' . current_path() . ' request_path=' . request_path());
-  }
-
-}
diff --git a/core/modules/system/tests/modules/url_alter_test/url_alter_test.routing.yml b/core/modules/system/tests/modules/url_alter_test/url_alter_test.routing.yml
deleted file mode 100644
index 843fad6f16b807504a3f1ded0b5098603a6d092a..0000000000000000000000000000000000000000
--- a/core/modules/system/tests/modules/url_alter_test/url_alter_test.routing.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-url_alter_test.foo:
-  path: '/url-alter-test/foo'
-  defaults:
-    _controller: '\Drupal\url_alter_test\Controller\URLAlterTestController::foo'
-  requirements:
-    _access: 'TRUE'
diff --git a/core/modules/update/src/UpdateManager.php b/core/modules/update/src/UpdateManager.php
index 21cfe806fcbb6b44c8dae6e57ffe08fe3e84dde4..065243068ec9ddf1f0d69f5ae08637320b893fd7 100644
--- a/core/modules/update/src/UpdateManager.php
+++ b/core/modules/update/src/UpdateManager.php
@@ -148,18 +148,22 @@ public function projectStorage($key) {
 
     // On certain paths, we should clear the data and recompute the projects for
     // update status of the site to avoid presenting stale information.
-    $paths = array(
-      'admin/modules',
-      'admin/modules/update',
-      'admin/appearance',
-      'admin/appearance/update',
-      'admin/reports',
-      'admin/reports/updates',
-      'admin/reports/updates/update',
-      'admin/reports/status',
-      'admin/reports/updates/check',
+    $route_names = array(
+      'update.theme_update',
+      'system.modules_list',
+      'system.theme_install',
+      'update.module_update',
+      'update.module_install',
+      'update.status',
+      'update.report_update',
+      'update.report_install',
+      'update.settings',
+      'system.status',
+      'update.manual_status',
+      'update.confirmation_page',
+      'system.themes_page',
     );
-    if (in_array(current_path(), $paths)) {
+    if (in_array(\Drupal::routeMatch()->getRouteName(), $route_names)) {
       $this->keyValueStore->delete($key);
     }
     else {
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index cdfc40ce8c51b18876be6d28ed0a80442fea9afc..542e0c570f1f13594ef01cfbbd1ed34f62d9f5c8 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -120,25 +120,25 @@ function update_page_top() {
   /** @var \Drupal\Core\Routing\AdminContext $admin_context */
   $admin_context = \Drupal::service('router.admin_context');
   if ($admin_context->isAdminRoute(\Drupal::request()->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) && \Drupal::currentUser()->hasPermission('administer site configuration')) {
-    $current_path = current_path();
-    switch ($current_path) {
+    $route_name = \Drupal::routeMatch()->getRouteName();
+    switch ($route_name) {
       // These pages don't need additional nagging.
-      case 'admin/appearance/update':
-      case 'admin/appearance/install':
-      case 'admin/modules/update':
-      case 'admin/modules/install':
-      case 'admin/reports/updates':
-      case 'admin/reports/updates/update':
-      case 'admin/reports/updates/install':
-      case 'admin/reports/updates/settings':
-      case 'admin/reports/status':
-      case 'admin/update/ready':
+      case 'update.theme_update':
+      case 'system.theme_install':
+      case 'update.module_update':
+      case 'update.module_install':
+      case 'update.status':
+      case 'update.report_update':
+      case 'update.report_install':
+      case 'update.settings':
+      case 'system.status':
+      case 'update.confirmation_page':
         return;
 
       // If we are on the appearance or modules list, display a detailed report
       // of the update status.
-      case 'admin/appearance':
-      case 'admin/modules':
+      case 'system.themes_page':
+      case 'system.modules_list':
         $verbose = TRUE;
         break;
 
diff --git a/core/modules/user/src/Plugin/Block/UserLoginBlock.php b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
index a2111cc7da6a6b0e4ea3ba7fa961e21d66dfe72e..350a19eebaf74e79178d357e4d695799312c599b 100644
--- a/core/modules/user/src/Plugin/Block/UserLoginBlock.php
+++ b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\Block;
 
+use Drupal\Core\Routing\UrlGeneratorTrait;
 use Drupal\Core\Url;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Block\BlockBase;
@@ -23,6 +24,8 @@
  */
 class UserLoginBlock extends BlockBase {
 
+  use UrlGeneratorTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -41,7 +44,7 @@ public function build() {
     unset($form['pass']['#description']);
     $form['name']['#size'] = 15;
     $form['pass']['#size'] = 15;
-    $form['#action'] = _url(current_path(), array('query' => drupal_get_destination(), 'external' => FALSE));
+    $form['#action'] = $this->url('<current>', [], ['query' => drupal_get_destination(), 'external' => FALSE]);
     // Build action links.
     $items = array();
     if (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY) {
diff --git a/core/modules/views/js/base.js b/core/modules/views/js/base.js
index e7aa903a6329e9ae1d87b8eed99369d192711bf1..d28b21d54c7abdb4d696935d553ba0b46dd130fd 100644
--- a/core/modules/views/js/base.js
+++ b/core/modules/views/js/base.js
@@ -62,7 +62,7 @@
    */
   Drupal.Views.getPath = function (href) {
     href = Drupal.Views.pathPortion(href);
-    href = href.substring(drupalSettings.path.basePath.length, href.length);
+    href = href.substring(drupalSettings.path.baseUrl.length, href.length);
     // 3 is the length of the '?q=' added to the url without clean urls.
     if (href.substring(0, 3) === '?q=') {
       href = href.substring(3, href.length);
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 507758c05c41d627fa7bf394ab5839472edb9dca..8d5eeca273ca18ff4f951d6d4f170a4a379a41f7 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -15,6 +15,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Url;
 use Drupal\views\Plugin\Derivative\ViewsLocalTask;
 use Drupal\Core\Template\AttributeArray;
 use Drupal\views\ViewExecutable;
@@ -61,7 +62,7 @@ function views_views_pre_render($view) {
             'view_name' => $view->storage->id(),
             'view_display_id' => $view->current_display,
             'view_args' => String::checkPlain(implode('/', $view->args)),
-            'view_path' => String::checkPlain(current_path()),
+            'view_path' => String::checkPlain(Url::fromRoute('<current>')->toString()),
             'view_base_path' => $view->getPath(),
             'view_dom_id' => $view->dom_id,
             // To fit multiple views on a page, the programmer may have
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index d4fb797d86b1aa191ac5bdc24f3431a9e1bb318c..c3ab4d94f2d890ad2efb87fd56cbc312a586c6d2 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -301,10 +301,12 @@ function template_preprocess_views_view_summary(&$variables) {
   $active_urls = array(
     // Force system path.
     \Drupal::url('<current>', [], ['alias' => TRUE]),
-    _url(current_path(), array('alias' => TRUE)), // force system path
+    // Force system path.
+    Url::fromRouteMatch(\Drupal::routeMatch())->setOption('alias', TRUE)->toString(),
     // Could be an alias.
     \Drupal::url('<current>'),
-    _url(current_path()), // could be an alias
+    // Could be an alias.
+    Url::fromRouteMatch(\Drupal::routeMatch())->toString(),
   );
   $active_urls = array_combine($active_urls, $active_urls);
 
diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc
index 61bd9a81ad47b66a35d4f9e02fb3bd1047021452..aee3fbb5966539a28752432d08e2bc17ecb392a4 100644
--- a/core/modules/views_ui/admin.inc
+++ b/core/modules/views_ui/admin.inc
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
 
@@ -322,20 +323,31 @@ function views_ui_standard_display_dropdown(&$form, FormStateInterface $form_sta
 /**
  * Create the menu path for one of our standard AJAX forms based upon known
  * information about the form.
+ *
+ * @return \Drupal\Core\Url
+ *   The URL object pointing to the form URL.
  */
-function views_ui_build_form_path(FormStateInterface $form_state) {
+function views_ui_build_form_url(FormStateInterface $form_state) {
   $ajax = !$form_state->get('ajax') ? 'nojs' : 'ajax';
   $name = $form_state->get('view')->id();
   $form_key = $form_state->get('form_key');
   $display_id = $form_state->get('display_id');
-  $path = "admin/structure/views/$ajax/$form_key/$name/$display_id";
+
+  $form_key = str_replace('-', '_', $form_key);
+  $route_name = "views_ui.form_{$form_key}";
+  $route_parameters = [
+    'js' => $ajax,
+    'view' => $name,
+    'display_id' => $display_id
+  ];
+  $url = Url::fromRoute($route_name, $route_parameters);
   if ($type = $form_state->get('type')) {
-    $path .= '/' . $type;
+    $url->setRouteParameter('type', $type);
   }
   if ($id = $form_state->get('id')) {
-    $path .= '/' . $id;
+    $url->setRouteParameter('id', $id);
   }
-  return $path;
+  return $url;
 }
 
 /**
diff --git a/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php b/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
index bdad87b994338f840e13c2980652b80e5a6bb7c8..3f0ee624b33a972d25b8bcd95df1a4f723fa8ce4 100644
--- a/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
+++ b/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
@@ -8,9 +8,11 @@
 namespace Drupal\views_ui\Form\Ajax;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Provides a form for configuring an item in the Views UI.
@@ -51,7 +53,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL) {
     $view = $form_state->get('view');
     $display_id = $form_state->get('display_id');
     $type = $form_state->get('type');
@@ -173,7 +175,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         '#submit' => array(array($this, 'remove')),
         '#limit_validation_errors' => array(array('override')),
         '#ajax' => array(
-          'path' => current_path(),
+          'url' => Url::fromRoute('<current>'),
         ),
       );
     }
diff --git a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
index 6d558cd6564c6ada127c48b10910adaadcc9279e..e265ce7b71e52cc6e389d1503d06d512e016941e 100644
--- a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
+++ b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
@@ -147,11 +147,11 @@ public function getForm(ViewStorageInterface $view, $display_id, $js) {
       $form_class = get_class($form_state->getFormObject());
 
       $form_state->setUserInput(array());
-      $form_path = views_ui_build_form_path($form_state);
+      $form_url = views_ui_build_form_url($form_state);
       if (!$form_state->get('ajax')) {
-        return new RedirectResponse(_url($form_path, array('absolute' => TRUE)));
+        return new RedirectResponse($form_url->setAbsolute()->toString());
       }
-      $form_state->set('path', $form_path);
+      $form_state->set('url', $form_url);
       $response = views_ajax_form_wrapper($form_class, $form_state);
     }
     elseif (!$form_state->get('ajax')) {
diff --git a/core/modules/views_ui/src/ViewPreviewForm.php b/core/modules/views_ui/src/ViewPreviewForm.php
index bdfb80f5513f413e98dd8329fba2712bc56260f0..38b6aa503a59d64f2fa34be5af7c515de2d1e4e1 100644
--- a/core/modules/views_ui/src/ViewPreviewForm.php
+++ b/core/modules/views_ui/src/ViewPreviewForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_ui;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 
 /**
  * Form controller for the Views preview form.
@@ -87,7 +88,7 @@ protected function actions(array $form, FormStateInterface $form_state) {
         '#submit' => array('::submitPreview'),
         '#id' => 'preview-submit',
         '#ajax' => array(
-          'path' => 'admin/structure/views/view/' . $view->id() . '/preview/' . $this->displayID,
+          'url' => Url::fromRoute('entity.view.preview_form', ['view' => $view->id(), 'display_id' => $this->displayID]),
           'wrapper' => 'views-preview-wrapper',
           'event' => 'click',
           'progress' => array('type' => 'fullscreen'),
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 75c309c2bd54d512bd7b36907923625dc5b9c574..971649968596a550066e20c167bfce1c190aba15 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -22,6 +22,9 @@
 use Drupal\views\Plugin\views\query\Sql;
 use Drupal\views\Entity\View;
 use Drupal\views\ViewStorageInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Stores UI related temporary settings.
@@ -324,7 +327,7 @@ public function getStandardButtons(&$form, FormStateInterface $form_state, $form
     // Views provides its own custom handling of AJAX form submissions. Usually
     // this happens at the same path, but custom paths may be specified in
     // $form_state.
-    $form_path = $form_state->get('path') ?: current_path();
+    $form_url = $form_state->get('url') ?: Url::fromRouteMatch(\Drupal::routeMatch());
 
     // Forms that are purely informational set an ok_button flag, so we know not
     // to create an "Apply" button for them.
@@ -341,7 +344,7 @@ public function getStandardButtons(&$form, FormStateInterface $form_state, $form
         '#submit' => array(array($this, 'standardSubmit')),
         '#button_type' => 'primary',
         '#ajax' => array(
-          'path' => $form_path,
+          'url' => $form_url,
         ),
       );
       // Form API button click detection requires the button's #value to be the
@@ -369,7 +372,7 @@ public function getStandardButtons(&$form, FormStateInterface $form_state, $form
       '#submit' => array($cancel_submit),
       '#validate' => array(),
       '#ajax' => array(
-        'path' => $form_path,
+        'path' => $form_url,
       ),
       '#limit_validation_errors' => array(),
     );
@@ -557,7 +560,8 @@ public function endQueryCapture() {
 
   public function renderPreview($display_id, $args = array()) {
     // Save the current path so it can be restored before returning from this function.
-    $old_q = current_path();
+    $request_stack = \Drupal::requestStack();
+    $current_request = $request_stack->getCurrentRequest();
 
     // Determine where the query and performance statistics should be output.
     $config = \Drupal::config('views.settings');
@@ -606,15 +610,22 @@ public function renderPreview($display_id, $args = array()) {
       }
 
       // Make view links come back to preview.
-      $this->override_path = 'admin/structure/views/view/' . $this->id() . '/preview/' . $display_id;
 
       // Also override the current path so we get the pager.
-      $original_path = current_path();
-      $q = _current_path($this->override_path);
-      if ($args) {
-        $q .= '/' . implode('/', $args);
-        _current_path($q);
+      $request = new Request();
+      $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'entity.view.preview_form');
+      $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, \Drupal::service('router.route_provider')->getRouteByName('entity.view.preview_form'));
+      $request->attributes->set('view', $this->storage);
+      $request->attributes->set('display_id', $display_id);
+      $raw_parameters = new ParameterBag();
+      $raw_parameters->set('view', $this->id());
+      $raw_parameters->set('display_id', $display_id);
+      $request->attributes->set('_raw_variables', $raw_parameters);
+
+      foreach ($args as $key => $arg) {
+        $request->attributes->set('arg_' . $key, $arg);
       }
+      $request_stack->push($request);
 
       // Suppress contextual links of entities within the result set during a
       // Preview.
@@ -642,10 +653,6 @@ public function renderPreview($display_id, $args = array()) {
 
       views_ui_contextual_links_suppress_pop();
 
-      // Reset variables.
-      unset($this->override_path);
-      _current_path($original_path);
-
       // Prepare the query information and statistics to show either above or
       // below the view preview.
       if ($show_info || $show_query || $show_stats) {
@@ -757,7 +764,11 @@ public function renderPreview($display_id, $args = array()) {
       $output .= $preview . drupal_render($table);
     }
 
-    _current_path($old_q);
+    // Ensure that we just remove an additional request we pushed earlier.
+    // This could happen if $errors was not empty.
+    if ($request_stack->getCurrentRequest() != $current_request) {
+      $request_stack->pop();
+    }
     return $output;
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php b/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
index 17e503522546a8ed14d97657d634da14e70308aa..01c6ab9ea4feb9e95b69459f352635666c3df098 100644
--- a/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
+++ b/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
@@ -37,7 +37,8 @@ protected function setUp() {
         ),
       )
     );
-    $this->pathMatcher = new PathMatcher($config_factory_stub);
+    $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
+    $this->pathMatcher = new PathMatcher($config_factory_stub, $route_match);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index 119eee6d78b7b64ec07c64878d458cbd8bbc3d3f..a93226a37e310d9302d8243405c2caa0bc4c8732 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -9,12 +9,14 @@
 
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Url;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\ParameterBag;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Route;
 
 /**
  * @coversDefaultClass \Drupal\Core\Url
@@ -217,6 +219,37 @@ public function testGetUriForExternalUrl() {
     $this->assertEquals('http://example.com/test', $url->getUri());
   }
 
+  /**
+   * Tests the getInternalPath method().
+   *
+   * @param \Drupal\Core\Url[] $urls
+   *   Array of URL objects.
+   *
+   * @covers ::getInternalPath
+   *
+   * @depends testUrlFromRequest
+   */
+  public function testGetInternalPath($urls) {
+    $map = [];
+    $map[] = ['view.frontpage.page_1', [], '/node'];
+    $map[] = ['node_view', ['node' => '1'], '/node/1'];
+    $map[] = ['node_edit', ['node' => '2'], '/node/2/edit'];
+
+    foreach ($urls as $index => $url) {
+      // Clone the url so that there is no leak of internal state into the
+      // other ones.
+      $url = clone $url;
+      $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
+      $url_generator->expects($this->once())
+        ->method('getPathFromRoute')
+        ->will($this->returnValueMap($map, $index));
+      $url->setUrlGenerator($url_generator);
+
+      $url->getInternalPath();
+      $url->getInternalPath();
+    }
+  }
+
   /**
    * Tests the toString() method.
    *
@@ -373,6 +406,17 @@ public function testRenderAccess($access) {
     $this->assertEquals($access, TestUrl::renderAccess($element));
   }
 
+  /**
+   * Tests the fromRouteMatch() method.
+   */
+  public function testFromRouteMatch() {
+    $route = new Route('/test-route/{foo}');
+    $route_match = new RouteMatch('test_route', $route, ['foo' => (object) [1]], ['foo' => 1]);
+    $url = Url::fromRouteMatch($route_match);
+    $this->assertSame('test_route', $url->getRouteName());
+    $this->assertEquals(['foo' => '1'] , $url->getRouteParameters());
+  }
+
   /**
    * Creates a mock access manager for the access tests.
    *