diff --git a/core/core.services.yml b/core/core.services.yml
index 9c3f606..244ccd4 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -555,7 +555,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 9e693f5..761cd74 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -451,18 +451,21 @@ 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 \Drupal\Core\Url) {
+        $options = UrlHelper::parse($redirect);
+        if (parse_url($options['path'], PHP_URL_SCHEME)) {
+          $redirect = Url::fromUri($options['path'], $options);
+        }
+        else {
+          $options = UrlHelper::parse($redirect);
+          $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);
     }
@@ -481,16 +484,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/common.inc b/core/includes/common.inc
index 4163da2..b2f4a58 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1473,9 +1473,12 @@ 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'];
+          /** @var  $request */
+          $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_is_admin = FALSE;
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 0bffd39..bc05009 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;
 
 /**
@@ -839,7 +840,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/lib/Drupal/Core/Path/PathMatcher.php b/core/lib/Drupal/Core/Path/PathMatcher.php
index 95c56dd..f39a839 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.
@@ -43,13 +45,23 @@ 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,8 @@ 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());
+      $url = Url::fromRouteMatch($this->routeMatch);
+      $this->isCurrentFrontPage = ($url->getRouteName() && $url->getInternalPath() == $this->getFrontPagePath());
     }
     return $this->isCurrentFrontPage;
   }
@@ -98,6 +111,7 @@ public function isFrontPage() {
   protected function getFrontPagePath() {
     // Lazy-load front page config.
     if (!isset($this->frontPage)) {
+      // @todo page.front should store the route name.
       $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 d9888c0..bd30b47 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 6ec6e11..09572c9 100644
--- a/core/lib/Drupal/Core/Routing/NullGenerator.php
+++ b/core/lib/Drupal/Core/Routing/NullGenerator.php
@@ -38,6 +38,9 @@ protected function getRoute($name) {
     if ($name === '<front>') {
       return new Route('/');
     }
+    else if ($name == '<current>') {
+      return new Route($this->requestStack->getCurrentRequest()->getPathInfo());
+    }
     throw new RouteNotFoundException();
   }
 
diff --git a/core/lib/Drupal/Core/Routing/NullRouteMatch.php b/core/lib/Drupal/Core/Routing/NullRouteMatch.php
index 0ef2c3b..1e31f72 100644
--- a/core/lib/Drupal/Core/Routing/NullRouteMatch.php
+++ b/core/lib/Drupal/Core/Routing/NullRouteMatch.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
diff --git a/core/lib/Drupal/Core/Routing/RouteMatch.php b/core/lib/Drupal/Core/Routing/RouteMatch.php
index eafb184..2817c50 100644
--- a/core/lib/Drupal/Core/Routing/RouteMatch.php
+++ b/core/lib/Drupal/Core/Routing/RouteMatch.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Url;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\ParameterBag;
 use Symfony\Component\HttpFoundation\Request;
diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index 9ea38b2..b9b3412 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;
@@ -87,6 +88,13 @@ class Url {
   protected $uri;
 
   /**
+   * Stores the internal path, if already requested by getInternalPath
+   *
+   * @var string
+   */
+  protected $internalPath;
+
+  /**
    * Constructs a new Url object.
    *
    * In most cases, use Url::fromRoute() or Url::fromUri() rather than
@@ -166,6 +174,18 @@ public static function fromRoute($route_name, $route_parameters = array(), $opti
   }
 
   /**
+   * 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) {
+    return new static($route_match->getRouteName(), $route_match->getRawParameters()->all());
+  }
+
+  /**
    * Creates a new Url object for a URI that does not have a Drupal route.
    *
    * This method is for generating URLs for URIs that do not have Drupal
@@ -510,7 +530,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,11 +606,11 @@ 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;
     return $this;
   }
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index c432706..82d6044 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 ce13994..dcfad00 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 0707714..6b0a37b 100644
--- a/core/misc/machine-name.js
+++ b/core/misc/machine-name.js
@@ -156,7 +156,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 6cb97ba..2e440a8 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 7a9e05f..34c20e8 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 ab0c6a8..d5a3e3d 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 601a149..9399122 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 90f318b..c4b0172 100644
--- a/core/modules/simpletest/src/InstallerTestBase.php
+++ b/core/modules/simpletest/src/InstallerTestBase.php
@@ -162,13 +162,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 730f84f..b1ac9e2 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -920,12 +920,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/Path/UrlAlterFunctionalTest.php b/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php
index 7f64ddb..56728c1 100644
--- a/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php
+++ b/core/modules/system/src/Tests/Path/UrlAlterFunctionalTest.php
@@ -75,15 +75,6 @@ function testUrlAlter() {
   }
 
   /**
-   * 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.
    *
    * @param $original
diff --git a/core/modules/system/src/Tests/Theme/ThemeTest.php b/core/modules/system/src/Tests/Theme/ThemeTest.php
index bee40f1..1a456de 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,17 @@ 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');
+    $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::service('current_route_match', NULL);
+    \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 0d41bba..5b8c4ba 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -240,7 +240,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');
 }
 
@@ -248,7 +253,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');
 }
 
diff --git a/core/modules/system/tests/modules/system_test/system_test.module b/core/modules/system/tests/modules/system_test/system_test.module
index 8024680..62e9867 100644
--- a/core/modules/system/tests/modules/system_test/system_test.module
+++ b/core/modules/system/tests/modules/system_test/system_test.module
@@ -99,16 +99,16 @@ function system_test_lock_exit() {
  * Implements hook_page_attachments().
  */
 function system_test_page_attachments(array &$page) {
-  $menu_item['path'] = current_path();
+  $route_name = \Drupal::routeMatch()->getRouteName();
   $main_content_display = &drupal_static('system_main_content_added', FALSE);
 
-  if ($menu_item['path'] == 'system-test/main-content-fallback') {
+  if ($route_name == 'system_test.main_content_fallback') {
     // Get the main content, to e.g. dynamically attach an asset.
     drupal_set_page_content();
     // Indicate we don't want to override the main content.
     $main_content_display = FALSE;
   }
-  elseif ($menu_item['path'] == 'system-test/main-content-handling') {
+  elseif ($route_name == 'system_test.main_content_handling') {
     // Set the main content.
     drupal_set_page_content('<div id="system-test-content">Overridden!</div>');
   }
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 da06222..0000000
--- 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 c12c7cb..0000000
--- 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:
-    _content: '\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 21cfe80..0652430 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 cdfc40c..32f0d6f 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -120,25 +120,26 @@ 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':
+      // @todo find out the corresponding route for that.
+      // case 'admin/appearance/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/views/js/base.js b/core/modules/views/js/base.js
index e7aa903..69fd6a3 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, 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 02e9f52..c39e651 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 d4fb797..c3ab4d9 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 61bd9a8..aee3fbb 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 90de6d9..9f4558b 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 6d558cd..e265ce7 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 bdfb80f..38b6aa5 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 75c309c..9716499 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 17e5035..01c6ab9 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/Routing/RouteMatchTest.php b/core/tests/Drupal/Tests/Core/Routing/RouteMatchTest.php
index 6aab6f4..cc18a71 100644
--- a/core/tests/Drupal/Tests/Core/Routing/RouteMatchTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/RouteMatchTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Core\Routing;
 
 use Drupal\Core\Routing\RouteMatch;
+use Drupal\Core\Url;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\ParameterBag;
@@ -63,6 +64,9 @@ public function testRouteMatchFromRequest() {
     $route_match = RouteMatch::createFromRequest($request);
     $this->assertSame(array('foo' => $foo), $route_match->getParameters()->all());
     $this->assertSame(array('foo' => '1'), $route_match->getRawParameters()->all());
+    $url = Url::fromRouteMatch($route_match);
+    $this->assertSame('test_route', $url->getRouteName());
+    $this->assertSame(['foo' => '1'] , $url->getRouteParameters());
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index 119eee6..a0dc8cd 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -218,6 +218,37 @@ public function testGetUriForExternalUrl() {
   }
 
   /**
+   * 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.
    *
    * @param \Drupal\Core\Url[] $urls
