diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index be5171e..4f72878 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -347,16 +347,10 @@ function template_preprocess_menu_local_task(&$variables) {
     '#options' => $link['localized_options'],
   );
 
-  if (!empty($link['href'])) {
-    // @todo - Remove this once all pages are converted to routes.
-    $variables['link']['#href'] = $link['href'];
-  }
-  else {
-    $variables['link'] += array(
-      '#route_name' => $link['route_name'],
-      '#route_parameters' => $link['route_parameters'],
-    );
-  }
+  $variables['link'] += array(
+    '#route_name' => $link['route_name'],
+    '#route_parameters' => $link['route_parameters'],
+  );
 }
 
 /**
@@ -394,10 +388,6 @@ function template_preprocess_menu_local_action(&$variables) {
       '#route_parameters' => $link['route_parameters'],
     );
   }
-  else {
-    // @todo - Remove this once all pages are converted to routes.
-    $variables['link']['#href'] = $link['href'];
-  }
 }
 
 /**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index f136ca1..1590143 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -977,22 +977,22 @@ function template_preprocess_links(&$variables) {
     foreach ($links as $key => $link) {
       $item = array();
       $link += array(
-        'href' => NULL,
         'route_name' => NULL,
         'route_parameters' => NULL,
         'ajax' => NULL,
+        'url' => NULL,
       );
 
       $li_attributes = array('class' => array());
       // Use the array key as class name.
       $li_attributes['class'][] = drupal_html_class($key);
 
-      $keys = array('title', 'href', 'route_name', 'route_parameters');
+      $keys = array('title', 'url', 'route_name', 'route_parameters');
       $link_element = array(
         '#type' => 'link',
         '#title' => $link['title'],
         '#options' => array_diff_key($link, array_combine($keys, $keys)),
-        '#href' => $link['href'],
+        '#url' => $link['url'],
         '#route_name' => $link['route_name'],
         '#route_parameters' => $link['route_parameters'],
         '#ajax' => $link['ajax'],
@@ -1000,7 +1000,7 @@ function template_preprocess_links(&$variables) {
 
       // Handle links and ensure that the active class is added on the LIs, but
       // only if the 'set_active_class' option is not empty.
-      if (isset($link['href']) || isset($link['route_name'])) {
+      if (isset($link['route_name']) || isset($link['url'])) {
         if (!empty($variables['set_active_class'])) {
 
           // Also enable set_active_class for the contained link.
@@ -1018,11 +1018,11 @@ function template_preprocess_links(&$variables) {
             $li_attributes['data-drupal-link-query'] = Json::encode($query);
           }
 
-          if (isset($link['route_name'])) {
-            $path = \Drupal::service('url_generator')->getPathFromRoute($link['route_name'], $link['route_parameters']);
+          if (isset($link['url'])) {
+            $path = $link['url']->toString();
           }
-          else {
-            $path = $link['href'];
+          elseif (isset($link['route_name'])) {
+            $path = \Drupal::urlGenerator()->getPathFromRoute($link['route_name'], $link['route_parameters']);
           }
 
           // Add a "data-drupal-link-system-path" attribute to let the
@@ -1032,6 +1032,9 @@ function template_preprocess_links(&$variables) {
 
         $item['link'] = $link_element;
       }
+      elseif (isset($link['href'])) {
+        throw new \Exception(String::format('href not allowed @href', ['@href' => $link['href']]));
+      }
 
       // Handle title-only text items.
       $text = (!empty($link['html']) ? $link['title'] : String::checkPlain($link['title']));
diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php
index 407b9d7..09d579d 100644
--- a/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -222,7 +222,7 @@ protected function actions(array $form, FormStateInterface $form_state) {
           'class' => array('button', 'button--danger'),
         ),
       );
-      $actions['delete'] += $route_info->toRenderArray();
+      $actions['delete']['#url'] = $route_info;
     }
 
     return $actions;
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/MailToFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/MailToFormatter.php
index 58f6c6b..19311b5 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/MailToFormatter.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/MailToFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Url;
 
 /**
  * Plugin implementation of the 'email_mailto' formatter.
@@ -33,7 +34,7 @@ public function viewElements(FieldItemListInterface $items) {
       $elements[$delta] = array(
         '#type' => 'link',
         '#title' => $item->value,
-        '#href' => 'mailto:' . $item->value,
+        '#url' => Url::fromUri('mailto:' . $item->value),
       );
     }
 
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/UriLinkFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/UriLinkFormatter.php
index 762d5f3..d9d26b1 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/UriLinkFormatter.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/UriLinkFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Url;
 
 /**
  * Plugin implementation of the 'uri_link' formatter.
@@ -30,11 +31,13 @@ public function viewElements(FieldItemListInterface $items) {
     $elements = array();
 
     foreach ($items as $delta => $item) {
-      $elements[$delta] = array(
-        '#type' => 'link',
-        '#href' => $item->value,
-        '#title' => $item->value,
-      );
+      if (!$item->isEmpty()) {
+        $elements[$delta] = array(
+          '#type' => 'link',
+          '#url' => Url::fromUri($item->value),
+          '#title' => $item->value,
+        );
+      }
     }
 
     return $elements;
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php
index a823cac..feb4587 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php
@@ -61,4 +61,11 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
     );
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    return !isset($this->values['value']) || $this->values['value'] === '';
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php
index 605a5ab..d34799c 100644
--- a/core/lib/Drupal/Core/Language/LanguageManager.php
+++ b/core/lib/Drupal/Core/Language/LanguageManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\StringTranslation\TranslationWrapper;
+use Drupal\Core\Url;
 
 /**
  * Class responsible for providing language support on language-unaware sites.
@@ -239,7 +240,7 @@ public function getFallbackCandidates(array $context = array()) {
   /**
    * {@inheritdoc}
    */
-  public function getLanguageSwitchLinks($type, $path) {
+  public function getLanguageSwitchLinks($type, Url $url) {
     return array();
   }
 
diff --git a/core/lib/Drupal/Core/Language/LanguageManagerInterface.php b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
index e163c0c..783496c 100644
--- a/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
+++ b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Language;
 
 use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Core\Url;
 
 /**
  * Common interface for the language manager service.
@@ -181,13 +182,13 @@ public function getFallbackCandidates(array $context = array());
    *
    * @param string $type
    *   The language type.
-   * @param string $path
-   *   The internal path the switch links will be relative to.
+   * @param \Drupal\Core\Url $url
+   *   The URL the switch links will be relative to.
    *
    * @return array
    *   A keyed array of links ready to be themed.
    */
-  public function getLanguageSwitchLinks($type, $path);
+  public function getLanguageSwitchLinks($type, Url $url);
 
   /**
    * Sets the configuration override language.
diff --git a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
index f6ee14b..bf86365 100644
--- a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
+++ b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
@@ -113,7 +113,8 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
     $link = array(
       '#type' => 'link',
       '#title' => $this->menuLink->getTitle(),
-    ) + $this->menuLink->getUrlObject()->toRenderArray();
+      '#url' => $this->menuLink->getUrlObject(),
+    );
     $form['path'] = array(
       'link' => $link,
       '#type' => 'item',
diff --git a/core/lib/Drupal/Core/Render/Element/Link.php b/core/lib/Drupal/Core/Render/Element/Link.php
index 474e9f5..82ae2e8 100644
--- a/core/lib/Drupal/Core/Render/Element/Link.php
+++ b/core/lib/Drupal/Core/Render/Element/Link.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Render\Element;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Url as UrlObject;
 
 /**
@@ -77,19 +78,22 @@ public static function preRenderLink($element) {
       }
       // If #ajax['path] was not specified, use the href as Ajax request URL.
       if (!isset($element['#ajax']['path'])) {
+        throw new \Exception('Missing ajax path');
         $element['#ajax']['path'] = $element['#href'];
         $element['#ajax']['options'] = $element['#options'];
       }
       $element = static::preRenderAjaxForm($element);
     }
 
-    if (isset($element['#route_name'])) {
+    if (isset($element['#url'])) {
+      $element['#markup'] = \Drupal::l($element['#title'], $element['#url']);
+    }
+    elseif (isset($element['#route_name'])) {
       $element['#route_parameters'] = empty($element['#route_parameters']) ? array() : $element['#route_parameters'];
       $element['#markup'] = \Drupal::l($element['#title'], new UrlObject($element['#route_name'], $element['#route_parameters'], $element['#options']));
     }
-    else {
-      // @todo Convert to \Drupal::l(): https://www.drupal.org/node/2347045.
-      $element['#markup'] = _l($element['#title'], $element['#href'], $element['#options']);
+    elseif (isset($element['#href'])) {
+      throw new \Exception(String::format('href not allowed @href', ['@href' => $element['#href']]));
     }
     return $element;
   }
diff --git a/core/lib/Drupal/Core/Render/Element/Table.php b/core/lib/Drupal/Core/Render/Element/Table.php
index d82fda8..830f72e 100644
--- a/core/lib/Drupal/Core/Render/Element/Table.php
+++ b/core/lib/Drupal/Core/Render/Element/Table.php
@@ -281,7 +281,8 @@ public static function validateTable(&$element, FormStateInterface $form_state,
    *   $form['table'][$row]['edit'] = array(
    *     '#type' => 'link',
    *     '#title' => t('Edit'),
-   *     '#href' => 'thing/' . $row . '/edit',
+   *     '#route_name' => 'entity.test_entity.edit_form',
+   *     '#route_parameters' => ['test_entity' => $row],
    *   );
    * }
    * @endcode
diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index a6f0220..3388598 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -480,20 +480,14 @@ public function toArray() {
    *   An associative array suitable for a render array.
    */
   public function toRenderArray() {
-    if ($this->unrouted) {
-      return array(
-        '#href' => $this->getUri(),
-        '#options' => $this->getOptions(),
-      );
-    }
-    else {
-      return array(
-        '#route_name' => $this->getRouteName(),
-        '#route_parameters' => $this->getRouteParameters(),
-        '#options' => $this->getOptions(),
-        '#access_callback' => array(get_class(), 'renderAccess'),
-      );
+    $render_array = [
+      '#url' => $this,
+      '#options' => $this->getOptions(),
+    ];
+    if (!$this->unrouted) {
+      $render_array['#access_callback'] = [get_class(), 'renderAccess'];
     }
+    return $render_array;
   }
 
   /**
@@ -543,7 +537,7 @@ public function access(AccountInterface $account = NULL) {
    *   Returns TRUE if the current user has access to the url, otherwise FALSE.
    */
   public static function renderAccess(array $element) {
-    return (new static($element['#route_name'], $element['#route_parameters'], $element['#options']))->access();
+    return $element['#url']->access();
   }
 
   /**
diff --git a/core/modules/aggregator/src/FeedViewBuilder.php b/core/modules/aggregator/src/FeedViewBuilder.php
index 26523ab..22ed7ab 100644
--- a/core/modules/aggregator/src/FeedViewBuilder.php
+++ b/core/modules/aggregator/src/FeedViewBuilder.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\EntityViewBuilder;
 use Drupal\Core\Config\Config;
 use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -99,7 +100,7 @@ public function buildComponents(array &$build, array $entities, array $displays,
           $image_link = array(
             '#type' => 'link',
             '#title' => $link_title,
-            '#href' => $link_href,
+            '#uri' => Url::fromUri($link_href),
             '#options' => array(
               'attributes' => array('class' => array('feed-image')),
               'html' => TRUE,
diff --git a/core/modules/aggregator/src/ItemsImporter.php b/core/modules/aggregator/src/ItemsImporter.php
index af19325..3098f08 100644
--- a/core/modules/aggregator/src/ItemsImporter.php
+++ b/core/modules/aggregator/src/ItemsImporter.php
@@ -120,7 +120,7 @@ public function refresh(FeedInterface $feed) {
       // Parse the feed.
       try {
         if ($this->parserManager->createInstance($this->config->get('parser'))->parse($feed)) {
-          if ($feed->getWebsiteUrl()) {
+          if (!$feed->getWebsiteUrl()) {
             $feed->setWebsiteUrl($feed->getUrl());
           }
           $feed->setHash($hash);
diff --git a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
index f28ff0d..2710ced 100644
--- a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
+++ b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
@@ -164,7 +164,7 @@ public function build() {
 
       $more_link = array(
         '#type' => 'more_link',
-        '#href' => 'aggregator/sources/' . $feed->id(),
+        '#url' => $feed->urlInfo(),
         '#attributes' => array('title' => $this->t("View this feed's recent news.")),
       );
       $read_more = drupal_render($more_link);
diff --git a/core/modules/aggregator/src/Tests/AddFeedTest.php b/core/modules/aggregator/src/Tests/AddFeedTest.php
index 5b15d02..67fecf8 100644
--- a/core/modules/aggregator/src/Tests/AddFeedTest.php
+++ b/core/modules/aggregator/src/Tests/AddFeedTest.php
@@ -27,7 +27,7 @@ function testAddFeed() {
     $this->drupalGet('aggregator/sources/' . $feed->id());
     $this->assertResponse(200, 'Feed source exists.');
     $this->assertText($feed->label(), 'Page title');
-    $this->assertText($feed->label());
+    $this->assertRaw($feed->getWebsiteUrl());
 
     // Delete feed.
     $this->deleteFeed($feed);
@@ -54,7 +54,6 @@ function testAddLongFeed() {
     $this->drupalGet('aggregator/sources/' . $feed->id());
     $this->assertResponse(200, 'Long URL feed source exists.');
     $this->assertText($feed->label(), 'Page title');
-    $this->assertText($feed->label());
 
     // Delete feeds.
     $this->deleteFeed($feed);
diff --git a/core/modules/aggregator/src/Tests/AggregatorTestBase.php b/core/modules/aggregator/src/Tests/AggregatorTestBase.php
index 57fcf88..1696a2e 100644
--- a/core/modules/aggregator/src/Tests/AggregatorTestBase.php
+++ b/core/modules/aggregator/src/Tests/AggregatorTestBase.php
@@ -58,7 +58,9 @@ function createFeed($feed_url = NULL, array $edit = array()) {
 
     $fid = db_query("SELECT fid FROM {aggregator_feed} WHERE title = :title AND url = :url", array(':title' => $edit['title[0][value]'], ':url' => $edit['url[0][value]']))->fetchField();
     $this->assertTrue(!empty($fid), 'The feed found in database.');
-    return Feed::load($fid);
+    $feed = Feed::load($fid);
+    $feed->refreshItems();
+    return $feed;
   }
 
   /**
diff --git a/core/modules/aggregator/src/Tests/FeedParserTest.php b/core/modules/aggregator/src/Tests/FeedParserTest.php
index a6d44c7..bfda92c 100644
--- a/core/modules/aggregator/src/Tests/FeedParserTest.php
+++ b/core/modules/aggregator/src/Tests/FeedParserTest.php
@@ -33,7 +33,6 @@ protected function setUp() {
    */
   function testRSS091Sample() {
     $feed = $this->createFeed($this->getRSS091Sample());
-    $feed->refreshItems();
     $this->drupalGet('aggregator/sources/' . $feed->id());
     $this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->label())));
     $this->assertText('First example feed item title');
@@ -55,7 +54,6 @@ function testRSS091Sample() {
    */
   function testAtomSample() {
     $feed = $this->createFeed($this->getAtomSample());
-    $feed->refreshItems();
     $this->drupalGet('aggregator/sources/' . $feed->id());
     $this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->label())));
     $this->assertText('Atom-Powered Robots Run Amok');
@@ -69,7 +67,6 @@ function testAtomSample() {
    */
   function testHtmlEntitiesSample() {
     $feed = $this->createFeed($this->getHtmlEntitiesSample());
-    $feed->refreshItems();
     $this->drupalGet('aggregator/sources/' . $feed->id());
     $this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->label())));
     $this->assertRaw("Quote&quot; Amp&amp;");
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index cbf56ab..693e90c 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -93,10 +93,15 @@ function block_page_build(&$page) {
     $page['page_top']['backlink'] = array(
       '#type' => 'link',
       '#title' => t('Exit block region demonstration'),
-      '#href' => 'admin/structure/block' . (\Drupal::config('system.theme')->get('default') == $theme ? '' : '/list/' . $theme),
       '#options' => array('attributes' => array('class' => array('block-demo-backlink'))),
       '#weight' => -10,
     );
+    if (\Drupal::config('system.theme')->get('default') == $theme) {
+      $page['page_top']['backlink']['#url'] = Url::fromRoute('block.admin_display_theme', ['theme' => $theme]);
+    }
+    else {
+      $page['page_top']['backlink']['#url'] = Url::fromRoute('block.admin_display');
+    }
   }
 }
 
diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc
index 469267c..ca559ba 100644
--- a/core/modules/book/book.admin.inc
+++ b/core/modules/book/book.admin.inc
@@ -45,7 +45,8 @@ function theme_book_admin_table($variables) {
     $links = array();
     $links['view'] = array(
       'title' => t('View'),
-      'href' => $href,
+      'route_name' => 'entity.node.canonical',
+      'route_parameters' => ['node' => $nid],
     );
     if ($access) {
       $links['edit'] = array(
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index dc20b1d..274114c 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -12,6 +12,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Url;
 use Drupal\node\NodeInterface;
 use Drupal\node\NodeTypeInterface;
 use Drupal\Core\Language\LanguageInterface;
@@ -107,7 +108,8 @@ function book_node_links_alter(array &$node_links, NodeInterface $node, array &$
         if (($account->hasPermission('add content to books') || $account->hasPermission('administer book outlines')) && $access_control_handler->createAccess($child_type) && $node->isPublished() && $node->book['depth'] < BookManager::BOOK_MAX_DEPTH) {
           $links['book_add_child'] = array(
             'title' => t('Add child page'),
-            'href' => 'node/add/' . $child_type,
+            'route_name' => 'node.add',
+            'route_parameters' => ['node_type' => $child_type],
             'query' => array('parent' => $node->id()),
           );
         }
@@ -115,7 +117,11 @@ function book_node_links_alter(array &$node_links, NodeInterface $node, array &$
         if ($account->hasPermission('access printer-friendly version')) {
           $links['book_printer'] = array(
             'title' => t('Printer-friendly version'),
-            'href' => 'book/export/html/' . $node->id(),
+            'route_name' => 'book.export',
+            'route_parameters' => [
+              'type' => 'html',
+              'node' => $node->id(),
+            ],
             'attributes' => array('title' => t('Show a printer-friendly version of this book page and its sub-pages.'))
           );
         }
@@ -398,34 +404,34 @@ function template_preprocess_book_navigation(&$variables) {
     $build = array();
 
     if ($prev = $book_outline->prevLink($book_link)) {
-      $prev_href = \Drupal::url('entity.node.canonical', array('node' => $prev['nid']));
+      $prev_url = Url::fromRoute('entity.node.canonical', ['node' => $prev['nid']]);
       $build['#attached']['drupal_add_html_head_link'][][] = array(
         'rel' => 'prev',
-        'href' => $prev_href,
+        'url' => $prev_url,
       );
-      $variables['prev_url'] = $prev_href;
+      $variables['prev_url'] = $prev_url->toString();
       $variables['prev_title'] = String::checkPlain($prev['title']);
     }
 
     /** @var \Drupal\book\BookManagerInterface $book_manager */
     $book_manager = \Drupal::service('book.manager');
     if ($book_link['pid'] && $parent = $book_manager->loadBookLink($book_link['pid'])) {
-      $parent_href = \Drupal::url('entity.node.canonical', array('node' => $book_link['pid']));
+      $parent_url = Url::fromRoute('entity.node.canonical', ['node' => $book_link['nid']]);
       $build['#attached']['drupal_add_html_head_link'][][] = array(
         'rel' => 'up',
-        'href' => $parent_href,
+        'url' => $parent_url,
       );
-      $variables['parent_url'] = $parent_href;
+      $variables['parent_url'] = $parent_url->toString();
       $variables['parent_title'] = String::checkPlain($parent['title']);
     }
 
     if ($next = $book_outline->nextLink($book_link)) {
-      $next_href = \Drupal::url('entity.node.canonical', array('node' => $next['nid']));
+      $next_url = Url::fromRoute('entity.node.canonical', ['node' => $next['nid']]);
       $build['#attached']['drupal_add_html_head_link'][][] = array(
         'rel' => 'next',
-        'href' => $next_href,
+        'url' => $next_url,
       );
-      $variables['next_url'] = $next_href;
+      $variables['next_url'] = $next_url->toString();
       $variables['next_title'] = String::checkPlain($next['title']);
     }
   }
diff --git a/core/modules/comment/src/CommentViewBuilder.php b/core/modules/comment/src/CommentViewBuilder.php
index 524349d..da9ebbc 100644
--- a/core/modules/comment/src/CommentViewBuilder.php
+++ b/core/modules/comment/src/CommentViewBuilder.php
@@ -246,7 +246,7 @@ protected static function buildLinks(CommentInterface $entity, EntityInterface $
       if ($entity->access('delete')) {
         $links['comment-delete'] = array(
           'title' => t('Delete'),
-          'href' => "comment/{$entity->id()}/delete",
+          'url' => $entity->urlInfo('delete-form'),
           'html' => TRUE,
         );
       }
@@ -254,14 +254,20 @@ protected static function buildLinks(CommentInterface $entity, EntityInterface $
       if ($entity->access('update')) {
         $links['comment-edit'] = array(
           'title' => t('Edit'),
-          'href' => "comment/{$entity->id()}/edit",
+          'url' => $entity->urlInfo('edit-form'),
           'html' => TRUE,
         );
       }
       if ($entity->access('create')) {
         $links['comment-reply'] = array(
           'title' => t('Reply'),
-          'href' => "comment/reply/{$entity->getCommentedEntityTypeId()}/{$entity->getCommentedEntityId()}/{$entity->getFieldName()}/{$entity->id()}",
+          'route_name' => 'comment.reply',
+          'route_parameters' => [
+            'entity_type' => $entity->getCommentedEntityTypeId(),
+            'entity' => $entity->getCommentedEntityId(),
+            'field_name' => $entity->getFieldName(),
+            'pid' => $entity->id(),
+          ],
           'html' => TRUE,
         );
       }
@@ -283,7 +289,7 @@ protected static function buildLinks(CommentInterface $entity, EntityInterface $
     if (\Drupal::moduleHandler()->moduleExists('content_translation') && content_translation_translate_access($entity)->isAllowed()) {
       $links['comment-translations'] = array(
         'title' => t('Translate'),
-        'href' => 'comment/' . $entity->id() . '/translations',
+        'url' => $entity->urlInfo('drupal:content-translation-overview'),
         'html' => TRUE,
       );
     }
diff --git a/core/modules/comment/src/Form/CommentAdminOverview.php b/core/modules/comment/src/Form/CommentAdminOverview.php
index 723241a..68311d7 100644
--- a/core/modules/comment/src/Form/CommentAdminOverview.php
+++ b/core/modules/comment/src/Form/CommentAdminOverview.php
@@ -200,7 +200,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $type = '
           'data' => array(
             '#type' => 'link',
             '#title' => $comment->getSubject(),
-          ) + $comment_permalink->toRenderArray(),
+            '#url' => $comment_permalink,
+          ),
         ),
         'author' => drupal_render($username),
         'posted_in' => array(
diff --git a/core/modules/config/src/Controller/ConfigController.php b/core/modules/config/src/Controller/ConfigController.php
index 48b31df..8eb713f 100644
--- a/core/modules/config/src/Controller/ConfigController.php
+++ b/core/modules/config/src/Controller/ConfigController.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Diff\DiffFormatter;
+use Drupal\Core\Url;
 use Drupal\system\FileDownloadController;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -156,7 +157,7 @@ public function diff($source_name, $target_name = NULL, $collection = NULL) {
         ),
       ),
       '#title' => "Back to 'Synchronize configuration' page.",
-      '#href' => 'admin/config/development/configuration',
+      '#url' => Url::fromRoute('config.sync'),
     );
 
     return $build;
diff --git a/core/modules/config_translation/src/ConfigEntityMapper.php b/core/modules/config_translation/src/ConfigEntityMapper.php
index ce66ff6..9265d33 100644
--- a/core/modules/config_translation/src/ConfigEntityMapper.php
+++ b/core/modules/config_translation/src/ConfigEntityMapper.php
@@ -216,7 +216,10 @@ public function getOperations() {
     return array(
       'list' => array(
         'title' => $this->t('List'),
-        'href' => 'admin/config/regional/config-translation/' . $this->getPluginId(),
+        'route_name' => 'config_translation.entity_list',
+        'route_parameters' => [
+          'mapper_id' => $this->getPluginId(),
+        ],
       ),
     );
   }
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 49e4b67..bf6d612 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -743,13 +743,12 @@ function content_translation_page_alter(&$page) {
       foreach ($entity->getTranslationLanguages() as $language) {
         $url = $entity->urlInfo()
           ->setOption('language', $language)
-          ->setAbsolute()
-          ->toString();
+          ->setAbsolute();
         $page['#attached']['drupal_add_html_head_link'][] = array(
           array(
             'rel' => 'alternate',
             'hreflang' => $language->id,
-            'href' => $url,
+            'url' => $url,
           ),
           TRUE,
         );
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
index 154759f..e1242fb 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
@@ -76,7 +76,8 @@ public function viewElements(FieldItemListInterface $items) {
           $elements[$delta] = array(
             '#type' => 'link',
             '#title' => $label,
-          ) + $uri->toRenderArray();
+            '#url' => $uri,
+          );
 
           if (!empty($item->_attributes)) {
             $elements[$delta]['#options'] += array('attributes' => array());
diff --git a/core/modules/field_ui/src/EntityDisplayModeListBuilder.php b/core/modules/field_ui/src/EntityDisplayModeListBuilder.php
index 2a73834..6056508 100644
--- a/core/modules/field_ui/src/EntityDisplayModeListBuilder.php
+++ b/core/modules/field_ui/src/EntityDisplayModeListBuilder.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -118,7 +119,7 @@ public function render() {
       $table['#rows']['_add_new'][] = array(
         'data' => array(
           '#type' => 'link',
-          '#href' => "admin/structure/display-modes/$short_type/add/$entity_type",
+          '#url' => Url::fromRoute($short_type == 'view' ? 'field_ui.entity_view_mode_add_type' : 'field_ui.entity_form_mode_add_type', ['entity_type_id' => $entity_type]),
           '#title' => t('Add new %label @entity-type', array('%label' => $this->entityTypes[$entity_type]->getLabel(), '@entity-type' => $this->entityType->getLowercaseLabel())),
           '#options' => array(
             'html' => TRUE,
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index b4bf306..4d9833a 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -120,7 +120,8 @@ function forum_menu_local_tasks(&$data, $route_name) {
           '#theme' => 'menu_local_action',
           '#link' => array(
             'title' => t('Add new @node_type', array('@node_type' => entity_load('node_type', $type)->label())),
-            'href' => 'node/add/' . $type,
+            'route_name' => 'node.add',
+            'route_parameters' => ['node_type' => $type],
           ),
         );
         if ($forum_term && $forum_term->bundle() == $vid) {
diff --git a/core/modules/forum/src/Form/Overview.php b/core/modules/forum/src/Form/Overview.php
index eb05b3a..d897881 100644
--- a/core/modules/forum/src/Form/Overview.php
+++ b/core/modules/forum/src/Form/Overview.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Url;
 use Drupal\taxonomy\Form\OverviewTerms;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
@@ -65,7 +66,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     foreach (Element::children($form['terms']) as $key) {
       if (isset($form['terms'][$key]['#term'])) {
         $term = $form['terms'][$key]['#term'];
-        $form['terms'][$key]['term']['#href'] = 'forum/' . $term->id();
+        $form['terms'][$key]['term']['#url'] = Url::fromRoute('forum.page', ['taxonomy_term' => $term->id()]);
         unset($form['terms'][$key]['operations']['#links']['delete']);
         if (!empty($term->forum_container->value)) {
           $form['terms'][$key]['operations']['#links']['edit']['title'] = $this->t('edit container');
diff --git a/core/modules/forum/src/Plugin/Block/ForumBlockBase.php b/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
index f480892..edd7ac6 100644
--- a/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
+++ b/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
@@ -27,7 +27,7 @@ public function build() {
       $elements['forum_list'] = $node_title_list;
       $elements['forum_more'] = array(
         '#type' => 'more_link',
-        '#href' => 'forum',
+        '#route_name' => 'forum.index',
         '#attributes' => array('title' => $this->t('Read the latest forum topics.')),
       );
     }
diff --git a/core/modules/image/src/Form/ImageEffectFormBase.php b/core/modules/image/src/Form/ImageEffectFormBase.php
index 52d5b2c..addbcf6 100644
--- a/core/modules/image/src/Form/ImageEffectFormBase.php
+++ b/core/modules/image/src/Form/ImageEffectFormBase.php
@@ -96,7 +96,8 @@ public function buildForm(array $form, FormStateInterface $form_state, ImageStyl
     $form['actions']['cancel'] = array(
       '#type' => 'link',
       '#title' => $this->t('Cancel'),
-    ) + $this->imageStyle->urlInfo('edit-form')->toRenderArray();
+      '#url' => $this->imageStyle->urlInfo('edit-form'),
+    );
     return $form;
   }
 
diff --git a/core/modules/image/src/Form/ImageStyleEditForm.php b/core/modules/image/src/Form/ImageStyleEditForm.php
index 8703ee6..1b28d7f 100644
--- a/core/modules/image/src/Form/ImageStyleEditForm.php
+++ b/core/modules/image/src/Form/ImageStyleEditForm.php
@@ -126,12 +126,20 @@ public function form(array $form, FormStateInterface $form_state) {
       if ($is_configurable) {
         $links['edit'] = array(
           'title' => $this->t('Edit'),
-          'href' => 'admin/config/media/image-styles/manage/' . $this->entity->id() . '/effects/' . $key,
+          'route_name' => 'image.effect_edit_form',
+          'route_parameters' => [
+            'image_style' => $this->entity->id(),
+            'image_effect' => $key,
+          ],
         );
       }
       $links['delete'] = array(
         'title' => $this->t('Delete'),
-        'href' => 'admin/config/media/image-styles/manage/' . $this->entity->id() . '/effects/' . $key . '/delete',
+        'route_name' => 'image.effect_delete',
+        'route_parameters' => [
+          'image_style' => $this->entity->id(),
+          'image_effect' => $key,
+        ],
       );
       $form['effects'][$key]['operations'] = array(
         '#type' => 'operations',
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index d5e5b7f..b060d35 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -113,7 +113,8 @@ function theme_language_negotiation_configure_browser_form_table($variables) {
     $links = array();
     $links['delete'] = array(
       'title' => t('Delete'),
-      'href' => "admin/config/regional/language/detection/browser/delete/$key",
+      'route_name' => 'language.negotiation_browser_delete',
+      'route_parameters' => ['browser_langcode' => $key],
       'attributes' => array(
         'class' => array('image-style-link'),
       ),
diff --git a/core/modules/language/src/ConfigurableLanguageManager.php b/core/modules/language/src/ConfigurableLanguageManager.php
index 6699ab0..6345029 100644
--- a/core/modules/language/src/ConfigurableLanguageManager.php
+++ b/core/modules/language/src/ConfigurableLanguageManager.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageDefault;
 use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Url;
 use Drupal\language\Config\LanguageConfigFactoryOverrideInterface;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Symfony\Component\HttpFoundation\Request;
@@ -395,7 +396,7 @@ public function getFallbackCandidates(array $context = array()) {
   /**
    * {@inheritdoc}
    */
-  public function getLanguageSwitchLinks($type, $path) {
+  public function getLanguageSwitchLinks($type, Url $url) {
     $links = FALSE;
 
     if ($this->negotiator) {
@@ -403,7 +404,7 @@ public function getLanguageSwitchLinks($type, $path) {
         $reflector = new \ReflectionClass($method['class']);
 
         if ($reflector->implementsInterface('\Drupal\language\LanguageSwitcherInterface')) {
-          $result = $this->negotiator->getNegotiationMethodInstance($method_id)->getLanguageSwitchLinks($this->requestStack->getCurrentRequest(), $type, $path);
+          $result = $this->negotiator->getNegotiationMethodInstance($method_id)->getLanguageSwitchLinks($this->requestStack->getCurrentRequest(), $type, $url);
 
           if (!empty($result)) {
             // Allow modules to provide translations for specific links.
diff --git a/core/modules/language/src/LanguageSwitcherInterface.php b/core/modules/language/src/LanguageSwitcherInterface.php
index d6edd5b..0550dd4 100644
--- a/core/modules/language/src/LanguageSwitcherInterface.php
+++ b/core/modules/language/src/LanguageSwitcherInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\language;
 
+use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -21,12 +22,12 @@
    *   The current request.
    * @param string $type
    *   The language type.
-   * @param string $path
-   *   The path links should point to.
+   * @param \Drupal\Core\Url $url
+   *   The URL the switch links will be relative to.
    *
    * @return array
    *   An array of link arrays keyed by language code.
    */
-  public function getLanguageSwitchLinks(Request $request, $type, $path);
+  public function getLanguageSwitchLinks(Request $request, $type, Url $url);
 
 }
diff --git a/core/modules/language/src/Plugin/Block/LanguageBlock.php b/core/modules/language/src/Plugin/Block/LanguageBlock.php
index a3aba84..0502d2d 100644
--- a/core/modules/language/src/Plugin/Block/LanguageBlock.php
+++ b/core/modules/language/src/Plugin/Block/LanguageBlock.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -75,9 +76,9 @@ protected function blockAccess(AccountInterface $account) {
    */
   public function build() {
     $build = array();
-    $path = drupal_is_front_page() ? '<front>' : current_path();
+    $route_name = drupal_is_front_page() ? '<front>' : '<current>';
     $type = $this->getDerivativeId();
-    $links = $this->languageManager->getLanguageSwitchLinks($type, $path);
+    $links = $this->languageManager->getLanguageSwitchLinks($type, Url::fromRoute($route_name));
 
     if (isset($links->links)) {
       $build = array(
diff --git a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
index dc5617d..293ac62 100644
--- a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
+++ b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
+use Drupal\Core\Url;
 use Drupal\language\LanguageNegotiationMethodBase;
 use Drupal\language\LanguageSwitcherInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -121,7 +122,7 @@ public function processOutbound($path, &$options = array(), Request $request = N
   /**
    * {@inheritdoc}
    */
-  function getLanguageSwitchLinks(Request $request, $type, $path) {
+  public function getLanguageSwitchLinks(Request $request, $type, Url $url) {
     $links = array();
     $config = $this->config->get('language.negotiation')->get('session');
     $param = $config['parameter'];
@@ -132,7 +133,7 @@ function getLanguageSwitchLinks(Request $request, $type, $path) {
     foreach ($this->languageManager->getNativeLanguages() as $language) {
       $langcode = $language->id;
       $links[$langcode] = array(
-        'href' => $path,
+        'url' => $url,
         'title' => $language->getName(),
         'attributes' => array('class' => array('language-link')),
         'query' => $query,
diff --git a/core/modules/language/tests/language_test/src/Controller/LanguageTestController.php b/core/modules/language/tests/language_test/src/Controller/LanguageTestController.php
index 2935b7d..a5cb033 100644
--- a/core/modules/language/tests/language_test/src/Controller/LanguageTestController.php
+++ b/core/modules/language/tests/language_test/src/Controller/LanguageTestController.php
@@ -62,7 +62,7 @@ public function typeLinkActiveClass() {
       'no_language' => array(
         '#type' => 'link',
         '#title' => t('Link to the current path with no langcode provided.'),
-        '#href' => current_path(),
+        '#route_name' => '<current>',
         '#options' => array(
           'attributes' => array(
             'id' => 'no_lang_link',
@@ -73,7 +73,7 @@ public function typeLinkActiveClass() {
       'fr' => array(
         '#type' => 'link',
         '#title' => t('Link to a French version of the current path.'),
-        '#href' => current_path(),
+        '#route_name' => '<current>',
         '#options' => array(
           'language' => $languages['fr'],
           'attributes' => array(
@@ -85,7 +85,7 @@ public function typeLinkActiveClass() {
       'en' => array(
         '#type' => 'link',
         '#title' => t('Link to an English version of the current path.'),
-        '#href' => current_path(),
+        '#route_name' => '<current>',
         '#options' => array(
           'language' => $languages['en'],
           'attributes' => array(
diff --git a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
index ca753f8..3aabb67 100644
--- a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -163,13 +163,7 @@ public function viewElements(FieldItemListInterface $items) {
           '#title' => $link_title,
           '#options' => $url->getOptions(),
         );
-        if ($url->isExternal()) {
-          $element[$delta]['#href'] = $url->getUri();
-        }
-        else {
-          $element[$delta]['#route_name'] = $url->getRouteName();
-          $element[$delta]['#route_parameters'] = $url->getRouteParameters();
-        }
+        $element[$delta]['#url'] = $url;
 
         if (!empty($item->_attributes)) {
           $element[$delta]['#options'] += array ('attributes' => array());
diff --git a/core/modules/node/src/Controller/NodePreviewController.php b/core/modules/node/src/Controller/NodePreviewController.php
index 35c65d9..38effaa 100644
--- a/core/modules/node/src/Controller/NodePreviewController.php
+++ b/core/modules/node/src/Controller/NodePreviewController.php
@@ -36,7 +36,7 @@ public function view(EntityInterface $node_preview, $view_mode_id = 'full', $lan
       $build['#attached']['drupal_add_html_head_link'][] = array(
         array(
         'rel' => $rel,
-        'href' => $node_preview->url($rel),
+        'url' => $node_preview->urlInfo($rel),
         )
         , TRUE);
 
@@ -45,7 +45,7 @@ public function view(EntityInterface $node_preview, $view_mode_id = 'full', $lan
         $build['#attached']['drupal_add_html_head_link'][] = array(
           array(
             'rel' => 'shortlink',
-            'href' => $node_preview->url($rel, array('alias' => TRUE)),
+            'url' => $node_preview->urlInfo($rel, array('alias' => TRUE)),
           )
         , TRUE);
       }
diff --git a/core/modules/node/src/Controller/NodeViewController.php b/core/modules/node/src/Controller/NodeViewController.php
index 84559a5..c20b8a3 100644
--- a/core/modules/node/src/Controller/NodeViewController.php
+++ b/core/modules/node/src/Controller/NodeViewController.php
@@ -30,7 +30,7 @@ public function view(EntityInterface $node, $view_mode = 'full', $langcode = NUL
       $build['#attached']['drupal_add_html_head_link'][] = array(
         array(
           'rel' => $rel,
-          'href' => $node->url($rel),
+          'url' => $node->urlInfo($rel),
         ),
         TRUE,
       );
@@ -40,7 +40,7 @@ public function view(EntityInterface $node, $view_mode = 'full', $langcode = NUL
         $build['#attached']['drupal_add_html_head_link'][] = array(
           array(
             'rel' => 'shortlink',
-            'href' => $node->url($rel, array('alias' => TRUE)),
+            'url' => $node->urlInfo($rel, array('alias' => TRUE)),
           ),
           TRUE,
         );
diff --git a/core/modules/node/src/Form/NodePreviewForm.php b/core/modules/node/src/Form/NodePreviewForm.php
index 81fd61c..52f0267 100644
--- a/core/modules/node/src/Form/NodePreviewForm.php
+++ b/core/modules/node/src/Form/NodePreviewForm.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -81,7 +82,7 @@ public function buildForm(array $form, FormStateInterface $form_state, EntityInt
     $form['backlink'] = array(
       '#type' => 'link',
       '#title' => $this->t('Back to content editing'),
-      '#href' => $node->isNew() ? 'node/add/' . $node->bundle() :  'node/' . $node->id() . '/edit',
+      '#url' => $node->isNew() ? Url::fromRoute('node.add', ['node_type' => $node->bundle()]) : $node->urlInfo('edit-form'),
       '#options' => array('attributes' => array('class' => array('node-preview-backlink'))) + $query_options,
     );
 
diff --git a/core/modules/node/src/NodeListBuilder.php b/core/modules/node/src/NodeListBuilder.php
index c78915d..606da79 100644
--- a/core/modules/node/src/NodeListBuilder.php
+++ b/core/modules/node/src/NodeListBuilder.php
@@ -105,7 +105,8 @@ public function buildRow(EntityInterface $entity) {
       '#type' => 'link',
       '#title' => $entity->label(),
       '#suffix' => ' ' . drupal_render($mark),
-    ) + $uri->toRenderArray();
+      '#url' => $uri,
+    );
     $row['type'] = String::checkPlain(node_get_type_label($entity));
     $row['author']['data'] = array(
       '#theme' => 'username',
diff --git a/core/modules/node/src/NodeViewBuilder.php b/core/modules/node/src/NodeViewBuilder.php
index 8cf1c04..1136428 100644
--- a/core/modules/node/src/NodeViewBuilder.php
+++ b/core/modules/node/src/NodeViewBuilder.php
@@ -146,7 +146,7 @@ protected static function buildLinks(NodeInterface $entity, $view_mode) {
         'title' => t('Read more<span class="visually-hidden"> about @title</span>', array(
           '@title' => $node_title_stripped,
         )),
-        'href' => 'node/' . $entity->id(),
+        'url' => $entity->urlInfo(),
         'language' => $entity->language(),
         'html' => TRUE,
         'attributes' => array(
diff --git a/core/modules/node/src/Plugin/views/area/ListingEmpty.php b/core/modules/node/src/Plugin/views/area/ListingEmpty.php
index cba41c2..8804f2e 100644
--- a/core/modules/node/src/Plugin/views/area/ListingEmpty.php
+++ b/core/modules/node/src/Plugin/views/area/ListingEmpty.php
@@ -8,6 +8,7 @@
 namespace Drupal\node\Plugin\views\area;
 
 use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Url;
 use Drupal\views\Plugin\views\area\AreaPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -67,7 +68,7 @@ public function render($empty = FALSE) {
         '#theme' => 'links',
         '#links' => array(
           array(
-            'href' => 'node/add',
+            'url' => Url::fromRoute('node.add_page'),
             'title' => $this->t('Add content'),
           ),
         ),
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 2575128..d177860 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -258,7 +258,7 @@ function shortcut_renderable_links($shortcut_set = NULL) {
     $shortcut = \Drupal::entityManager()->getTranslationFromContext($shortcut);
     $links[] = array(
       'title' => $shortcut->label(),
-      'href' => $shortcut->path->value,
+      'url' => \Drupal::service('path.validator')->getUrlIfValid($shortcut->path->value),
     );
     $cache_tags = Cache::mergeTags($cache_tags, $shortcut->getCacheTag());
   }
@@ -378,7 +378,7 @@ function shortcut_toolbar() {
         'tab' => array(
           '#type' => 'link',
           '#title' => t('Shortcuts'),
-          '#href' => 'admin/config/user-interface/shortcut',
+          '#url' => Url::fromRoute('shortcut.set_admin'),
           '#attributes' => array(
             'title' => t('Shortcuts'),
             'class' => array('toolbar-icon', 'toolbar-icon-shortcut'),
diff --git a/core/modules/shortcut/src/Form/SetCustomize.php b/core/modules/shortcut/src/Form/SetCustomize.php
index e778d8c..2d026b5 100644
--- a/core/modules/shortcut/src/Form/SetCustomize.php
+++ b/core/modules/shortcut/src/Form/SetCustomize.php
@@ -64,11 +64,11 @@ public function form(array $form, FormStateInterface $form_state) {
 
       $links['edit'] = array(
         'title' => t('Edit'),
-        'href' => "admin/config/user-interface/shortcut/link/$id",
+        'url' => $shortcut->urlInfo(),
       );
       $links['delete'] = array(
         'title' => t('Delete'),
-        'href' => "admin/config/user-interface/shortcut/link/$id/delete",
+        'url' => $shortcut->urlInfo('delete-form'),
       );
       $form['shortcuts']['links'][$id]['operations'] = array(
         '#type' => 'operations',
diff --git a/core/modules/simpletest/src/Form/SimpletestResultsForm.php b/core/modules/simpletest/src/Form/SimpletestResultsForm.php
index 56d4f59..7d39496 100644
--- a/core/modules/simpletest/src/Form/SimpletestResultsForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestResultsForm.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormState;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 use Drupal\simpletest\TestDiscovery;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -238,7 +239,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $test_id
     $form['action']['return'] = array(
       '#type' => 'link',
       '#title' => $this->t('Return to list'),
-      '#href' => 'admin/config/development/testing',
+      '#url' => Url::fromRoute('simpletest.test_form'),
     );
 
     if (is_numeric($test_id)) {
diff --git a/core/modules/system/src/Controller/DbUpdateController.php b/core/modules/system/src/Controller/DbUpdateController.php
index da7e4c3..2a7992c 100644
--- a/core/modules/system/src/Controller/DbUpdateController.php
+++ b/core/modules/system/src/Controller/DbUpdateController.php
@@ -216,7 +216,8 @@ protected function info() {
       '#type' => 'link',
       '#title' => $this->t('Continue'),
       '#attributes' => array('class' => array('button', 'button--primary')),
-    ) + $url->toRenderArray();
+      '#url' => $url,
+    );
     return $build;
   }
 
@@ -620,12 +621,12 @@ public static function batchFinished($success, $results, $operations) {
   protected function helpfulLinks() {
     $links['front'] = array(
       'title' => $this->t('Front page'),
-      'href' => '<front>',
+      'route_name' => '<front>',
     );
     if ($this->account->hasPermission('access administration pages')) {
       $links['admin-pages'] = array(
         'title' => $this->t('Administration pages'),
-        'href' => 'admin',
+        'route_name' => 'system.admin',
       );
     }
     return $links;
diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php
index c1b2b73..b24f8ca 100644
--- a/core/modules/system/src/Form/ModulesListForm.php
+++ b/core/modules/system/src/Form/ModulesListForm.php
@@ -22,6 +22,7 @@
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -258,7 +259,7 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
         $row['links']['help'] = array(
           '#type' => 'link',
           '#title' => $this->t('Help'),
-          '#href' => 'admin/help/' . $module->getName(),
+          '#url' => Url::fromRoute('help.page', ['name' => $module->getName()]),
           '#options' => array('attributes' => array('class' =>  array('module-link', 'module-link-help'), 'title' => $this->t('Help'))),
         );
       }
@@ -270,7 +271,7 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
       $row['links']['permissions'] = array(
         '#type' => 'link',
         '#title' => $this->t('Permissions'),
-        '#href' => 'admin/people/permissions',
+        '#url' => Url::fromRoute('user.admin_permissions'),
         '#options' => array('fragment' => 'module-' . $module->getName(), 'attributes' => array('class' => array('module-link', 'module-link-permissions'), 'title' => $this->t('Configure permissions'))),
       );
     }
diff --git a/core/modules/system/src/Tests/Common/RenderElementTypesTest.php b/core/modules/system/src/Tests/Common/RenderElementTypesTest.php
index 9757a2b..73879ee 100644
--- a/core/modules/system/src/Tests/Common/RenderElementTypesTest.php
+++ b/core/modules/system/src/Tests/Common/RenderElementTypesTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Tests\Common;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Url;
 use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
@@ -112,7 +113,7 @@ function testMoreLink() {
         'name' => "#type 'more_link' anchor tag generation without extra classes",
         'value' => array(
           '#type' => 'more_link',
-          '#href' => 'http://drupal.org',
+          '#url' => Url::fromUri('http://drupal.org'),
         ),
         'expected' => '//div[@class="more-link"]/a[@href="http://drupal.org" and text()="More"]',
       ),
@@ -120,7 +121,7 @@ function testMoreLink() {
         'name' => "#type 'more_link' anchor tag generation with different link text",
         'value' => array(
           '#type' => 'more_link',
-          '#href' => 'http://drupal.org',
+          '#url' => Url::fromUri('http://drupal.org'),
           '#title' => 'More Titles',
         ),
         'expected' => '//div[@class="more-link"]/a[@href="http://drupal.org" and text()="More Titles"]',
@@ -129,7 +130,7 @@ function testMoreLink() {
         'name' => "#type 'more_link' anchor tag generation with attributes on wrapper",
         'value' => array(
           '#type' => 'more_link',
-          '#href' => 'http://drupal.org',
+          '#url' => Url::fromUri('http://drupal.org'),
           '#theme_wrappers' => array(
             'container' => array(
               '#attributes' => array(
@@ -145,9 +146,9 @@ function testMoreLink() {
         'name' => "#type 'more_link' anchor tag with a relative path",
         'value' => array(
           '#type' => 'more_link',
-          '#href' => 'a/link',
+          '#route_name' => 'router_test.1',
         ),
-        'expected' => '//div[@class="more-link"]/a[@href="' . _url('a/link') . '" and text()="More"]',
+        'expected' => '//div[@class="more-link"]/a[@href="' . _url('router_test/test1') . '" and text()="More"]',
       ),
       array(
         'name' => "#type 'more_link' anchor tag with a route",
@@ -162,7 +163,7 @@ function testMoreLink() {
         'name' => "#type 'more_link' anchor tag with an absolute path",
         'value' => array(
           '#type' => 'more_link',
-          '#href' => 'admin/content',
+          '#route_name' => 'system.admin_content',
           '#options' => array('absolute' => TRUE),
         ),
         'expected' => '//div[@class="more-link"]/a[@href="' . _url('admin/content', array('absolute' => TRUE)) . '" and text()="More"]',
@@ -171,7 +172,7 @@ function testMoreLink() {
         'name' => "#type 'more_link' anchor tag to the front page",
         'value' => array(
           '#type' => 'more_link',
-          '#href' => '<front>',
+          '#route_name' => '<front>',
         ),
         'expected' => '//div[@class="more-link"]/a[@href="' . _url('<front>') . '" and text()="More"]',
       ),
diff --git a/core/modules/system/src/Tests/Common/RenderTest.php b/core/modules/system/src/Tests/Common/RenderTest.php
index d07085c..033845f 100644
--- a/core/modules/system/src/Tests/Common/RenderTest.php
+++ b/core/modules/system/src/Tests/Common/RenderTest.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Url;
 use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
@@ -120,7 +121,7 @@ function testDrupalRenderBasics() {
             ),
           ),
           '#attributes' => array('id' => 'foo'),
-          '#href' => 'http://drupal.org',
+          '#url' => Url::fromUri('http://drupal.org'),
           '#title' => 'bar',
         ),
         'expected' => '<div class="baz"><a href="http://drupal.org" id="foo">bar</a></div>' . "\n",
@@ -131,7 +132,7 @@ function testDrupalRenderBasics() {
         'name' => '#theme_wrappers attribute disambiguation with undefined #theme attribute',
         'value' => array(
           '#type' => 'link',
-          '#href' => 'http://drupal.org',
+          '#url' => Url::fromUri('http://drupal.org'),
           '#title' => 'foo',
           '#theme_wrappers' => array(
             'container' => array(
diff --git a/core/modules/system/src/Tests/Common/RenderWebTest.php b/core/modules/system/src/Tests/Common/RenderWebTest.php
index 3e58fb0..52dca2d 100644
--- a/core/modules/system/src/Tests/Common/RenderWebTest.php
+++ b/core/modules/system/src/Tests/Common/RenderWebTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Tests\Common;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Url;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -105,13 +106,13 @@ function testDrupalRenderFormElements() {
     $element = array(
       '#type' => 'link',
       '#title' => $this->randomMachineName(),
-      '#href' => $this->randomMachineName(),
+      '#url' => Url::fromUri($this->randomMachineName()),
       '#options' => array(
         'absolute' => TRUE,
       ),
     );
     $this->assertRenderedElement($element, '//a[@href=:href and contains(., :title)]', array(
-      ':href' => _url($element['#href'], array('absolute' => TRUE)),
+      ':href' => $element['#url']->toString(),
       ':title' => $element['#title'],
     ));
 
diff --git a/core/modules/system/src/Tests/Common/UrlTest.php b/core/modules/system/src/Tests/Common/UrlTest.php
index 0097512..b719ebf 100644
--- a/core/modules/system/src/Tests/Common/UrlTest.php
+++ b/core/modules/system/src/Tests/Common/UrlTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Url;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -38,15 +39,10 @@ function testLinkXSS() {
     $sanitized_path = check_url(_url($path));
     $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by _l().', array('@path' => $path)));
 
-    // Test #type 'link'.
-    $link_array =  array(
-      '#type' => 'link',
-      '#title' => $this->randomMachineName(),
-      '#href' => $path,
-    );
-    $type_link = drupal_render($link_array);
+    // Test _url().
+    $link = _url($path);
     $sanitized_path = check_url(_url($path));
-    $this->assertTrue(strpos($type_link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by #theme', array('@path' => $path)));
+    $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered by #theme', array('@path' => $path)));
   }
 
   /**
@@ -60,7 +56,7 @@ function testLinkAttributes() {
       '#options' => array(
         'language' => $language,
       ),
-      '#href' => 'http://drupal.org',
+      '#url' => Url::fromUri('http://drupal.org'),
       '#title' => 'bar',
     );
     $langcode = $language->id;
@@ -122,7 +118,7 @@ function testLinkAttributes() {
     $type_link = array(
       '#type' => 'link',
       '#title' => $this->randomMachineName(),
-      '#href' => current_path(),
+      '#route_name' => '<current>',
       '#options' => array(
         'attributes' => array(
           'class' => array($class_theme),
@@ -149,7 +145,7 @@ function testLinkRenderArrayText() {
     $type_link_plain_array = array(
       '#type' => 'link',
       '#title' => 'foo',
-      '#href' => 'http://drupal.org',
+      '#url' => Url::fromUri('http://drupal.org'),
     );
     $type_link_plain = drupal_render($type_link_plain_array);
     $this->assertEqual($type_link_plain, $l);
@@ -158,7 +154,7 @@ function testLinkRenderArrayText() {
     $type_link_nested_array = array(
       '#type' => 'link',
       '#title' => array('#markup' => 'foo'),
-      '#href' => 'http://drupal.org',
+      '#url' => Url::fromUri('http://drupal.org'),
     );
     $type_link_nested = drupal_render($type_link_nested_array);
     $this->assertEqual($type_link_nested, $l);
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index f721626..c872f4b 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -412,7 +412,7 @@ function hook_menu_local_tasks(&$data, $route_name) {
     '#theme' => 'menu_local_action',
     '#link' => array(
       'title' => t('Add content'),
-      'href' => 'node/add',
+      'route_name' => 'node.add_page',
       'localized_options' => array(
         'attributes' => array(
           'title' => t('Add content'),
@@ -426,7 +426,7 @@ function hook_menu_local_tasks(&$data, $route_name) {
     '#theme' => 'menu_local_task',
     '#link' => array(
       'title' => t('Example tab'),
-      'href' => 'node/add',
+      'route_name' => 'node.add_page',
       'localized_options' => array(
         'attributes' => array(
           'title' => t('Add content'),
@@ -2277,7 +2277,7 @@ function hook_system_themes_page_alter(&$theme_groups) {
       // Add a foo link to each list of theme operations.
       $theme->operations[] = array(
         'title' => t('Foo'),
-        'href' => 'admin/appearance/foo',
+        'route_name' => 'system.themes_page',
         'query' => array('theme' => $theme->getName())
       );
     }
diff --git a/core/modules/system/tests/modules/ajax_test/ajax_test.module b/core/modules/system/tests/modules/ajax_test/ajax_test.module
index 6127b2e..870a157 100644
--- a/core/modules/system/tests/modules/ajax_test/ajax_test.module
+++ b/core/modules/system/tests/modules/ajax_test/ajax_test.module
@@ -11,6 +11,7 @@
 use Drupal\Core\Ajax\OpenModalDialogCommand;
 use Drupal\Core\Ajax\CloseDialogCommand;
 use Drupal\Core\Ajax\HtmlCommand;
+use Drupal\Core\Url;
 
 /**
  * Menu callback: Returns an element suitable for use by
@@ -108,7 +109,7 @@ function ajax_test_dialog_contents() {
     'cancel' => array(
       '#type' => 'link',
       '#title' => 'Cancel',
-      '#href' => '',
+      '#url' => Url::fromRoute('<front>'),
       '#attributes' => array(
         // This is a special class to which JavaScript assigns dialog closing
         // behavior.
diff --git a/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php b/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php
index ac0399f..ab25fde 100644
--- a/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php
+++ b/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\ajax_test\Controller;
 
+use Drupal\Core\Url;
+
 /**
  * Provides content for dialog tests.
  */
@@ -56,7 +58,7 @@ public function dialog() {
     $build['link'] = array(
       '#type' => 'link',
       '#title' => 'Link 1 (modal)',
-      '#href' => 'ajax-test/dialog-contents',
+      '#url' => Url::fromRoute('ajax_test.dialog_contents'),
       '#attributes' => array(
         'class' => array('use-ajax'),
         'data-accepts' => 'application/vnd.drupal-modal',
@@ -69,7 +71,7 @@ public function dialog() {
       '#links' => array(
         'link2' => array(
           'title' => 'Link 2 (modal)',
-          'href' => 'ajax-test/dialog-contents',
+          'url' => Url::fromRoute('ajax_test.dialog_contents'),
           'attributes' => array(
             'class' => array('use-ajax'),
             'data-accepts' => 'application/vnd.drupal-modal',
@@ -80,7 +82,7 @@ public function dialog() {
         ),
         'link3' => array(
           'title' => 'Link 3 (non-modal)',
-          'href' => 'ajax-test/dialog-contents',
+          'url' => Url::fromRoute('ajax_test.dialog_contents'),
           'attributes' => array(
             'class' => array('use-ajax'),
             'data-accepts' => 'application/vnd.drupal-dialog',
@@ -92,14 +94,14 @@ public function dialog() {
         ),
         'link4' => array(
           'title' => 'Link 4 (close non-modal if open)',
-          'href' => 'ajax-test/dialog-close',
+          'url' => Url::fromRoute('ajax_test.dialog_close'),
           'attributes' => array(
             'class' => array('use-ajax'),
           ),
         ),
         'link5' => array(
           'title' => 'Link 5 (form)',
-          'href' => 'ajax-test/dialog-form',
+          'url' => Url::fromRoute('ajax_test.dialog_form'),
           'attributes' => array(
             'class' => array('use-ajax'),
             'data-accepts' => 'application/vnd.drupal-modal',
@@ -107,7 +109,7 @@ public function dialog() {
         ),
         'link6' => array(
           'title' => 'Link 6 (entity form)',
-          'href' => 'admin/structure/contact/add',
+          'url' => Url::fromRoute('contact.form_add'),
           'attributes' => array(
             'class' => array('use-ajax'),
             'data-accepts' => 'application/vnd.drupal-modal',
@@ -119,7 +121,7 @@ public function dialog() {
         ),
         'link7' => array(
           'title' => 'Link 7 (non-modal, no target)',
-          'href' => 'ajax-test/dialog-contents',
+          'url' => Url::fromRoute('ajax_test.dialog_contents'),
           'attributes' => array(
             'class' => array('use-ajax'),
             'data-accepts' => 'application/vnd.drupal-dialog',
diff --git a/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php b/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php
index be4ce96..cf82dba 100644
--- a/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php
+++ b/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php
@@ -8,6 +8,7 @@
 namespace Drupal\common_test\Controller;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Response;
 
 /**
@@ -25,7 +26,7 @@ public function typeLinkActiveClass() {
       'no_query' => array(
         '#type' => 'link',
         '#title' => t('Link with no query string'),
-        '#href' => current_path(),
+        '#url' => Url::fromRoute('<current>'),
         '#options' => array(
           'set_active_class' => TRUE,
         ),
@@ -33,7 +34,7 @@ public function typeLinkActiveClass() {
       'with_query' => array(
         '#type' => 'link',
         '#title' => t('Link with a query string'),
-        '#href' => current_path(),
+        '#url' => Url::fromRoute('<current>'),
         '#options' => array(
           'query' => array(
             'foo' => 'bar',
@@ -45,7 +46,7 @@ public function typeLinkActiveClass() {
       'with_query_reversed' => array(
         '#type' => 'link',
         '#title' => t('Link with the same query string in reverse order'),
-        '#href' => current_path(),
+        '#url' => Url::fromRoute('<current>'),
         '#options' => array(
           'query' => array(
             'one' => 'two',
diff --git a/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php b/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php
index a02be18..7d2cb79 100644
--- a/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php
+++ b/core/modules/system/tests/modules/theme_test/src/EventSubscriber/ThemeTestSubscriber.php
@@ -44,7 +44,7 @@ public function onRequest(GetResponseEvent $event) {
       // returning output and theming the page as a whole.
       $more_link = array(
         '#type' => 'more_link',
-        '#href' => 'user',
+        '#route_name' => 'user.page',
         '#attributes' => array('title' => 'Themed output generated in a KernelEvents::REQUEST listener'),
       );
       $GLOBALS['theme_test_output'] = drupal_render($more_link);
diff --git a/core/modules/taxonomy/src/Form/OverviewTerms.php b/core/modules/taxonomy/src/Form/OverviewTerms.php
index 95e6178..ffe0ea1 100644
--- a/core/modules/taxonomy/src/Form/OverviewTerms.php
+++ b/core/modules/taxonomy/src/Form/OverviewTerms.php
@@ -225,7 +225,8 @@ public function buildForm(array $form, FormStateInterface $form_state, Vocabular
         '#prefix' => !empty($indentation) ? drupal_render($indentation) : '',
         '#type' => 'link',
         '#title' => $term->getName(),
-      ) + $term->urlInfo()->toRenderArray();
+        '#url' => $term->urlInfo(),
+      );
       if ($taxonomy_vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1) {
         $parent_fields = TRUE;
         $form['terms'][$key]['term']['tid'] = array(
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php
index 856b73e..4f57b2e 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -42,7 +42,8 @@ public function viewElements(FieldItemListInterface $items) {
         $elements[$delta] = array(
           '#type' => 'link',
           '#title' => $term->getName(),
-        ) + $term->urlInfo()->toRenderArray();
+          '#url' => $term->urlInfo(),
+        );
 
         if (!empty($item->_attributes)) {
           $elements[$delta]['#options'] += array('attributes' => array());
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index a715c0a..0de8dbd 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -113,7 +113,7 @@ function taxonomy_page_build(&$page) {
       $page['#attached']['drupal_add_html_head_link'][] = array(
         array(
           'rel' => $rel,
-          'href' => $term->url($rel),
+          'url' => $term->urlInfo($rel),
         ),
         TRUE,
       );
@@ -124,7 +124,7 @@ function taxonomy_page_build(&$page) {
         $page['#attached']['drupal_add_html_head_link'][] = array(
           array(
             'rel' => 'shortlink',
-            'href' => $term->url($rel, array('alias' => TRUE)),
+            'url' => $term->urlInfo($rel, array('alias' => TRUE)),
           ),
           TRUE,
         );
diff --git a/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php b/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php
index ef45d4e..5d83b7c 100644
--- a/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php
+++ b/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 
 /**
  * Plugin implementation of the 'telephone_link' formatter.
@@ -78,7 +79,7 @@ public function viewElements(FieldItemListInterface $items) {
         // itself as title.
         '#title' => $title_setting ?: $item->value,
         // Prepend 'tel:' to the telephone number.
-        '#href' => 'tel:' . rawurlencode(preg_replace('/\s+/', '', $item->value)),
+        '#url' => Url::fromUri('tel:' . rawurlencode(preg_replace('/\s+/', '', $item->value))),
         '#options' => array('external' => TRUE),
       );
 
diff --git a/core/modules/toolbar/src/Element/ToolbarItem.php b/core/modules/toolbar/src/Element/ToolbarItem.php
index 18ade46..4c2324a 100644
--- a/core/modules/toolbar/src/Element/ToolbarItem.php
+++ b/core/modules/toolbar/src/Element/ToolbarItem.php
@@ -33,7 +33,6 @@ public function getInfo() {
       'tab' => array(
         '#type' => 'link',
         '#title' => NULL,
-        '#href' => '',
       ),
     );
   }
diff --git a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
index 69dac7a..d0d96b0 100644
--- a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
+++ b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
@@ -17,7 +17,6 @@ function toolbar_test_toolbar() {
     'tab' => array(
       '#type' => 'link',
       '#title' => t('Test tab'),
-      '#href' => '',
       '#options' => array(
         'html' => FALSE,
         'attributes' => array(
diff --git a/core/modules/toolbar/toolbar.api.php b/core/modules/toolbar/toolbar.api.php
index ab9b75a..bce69ae 100644
--- a/core/modules/toolbar/toolbar.api.php
+++ b/core/modules/toolbar/toolbar.api.php
@@ -4,6 +4,7 @@
  * @file
  * Hooks provided by the toolbar module.
  */
+use Drupal\Core\Url;
 
 /**
  * @addtogroup hooks
@@ -72,7 +73,7 @@ function hook_toolbar() {
     'tab' => array(
       '#type' => 'link',
       '#title' => t('Home'),
-      '#href' => '<front>',
+      '#url' => Url::fromRoute('<front>'),
       '#options' => array(
         'attributes' => array(
           'title' => t('Home page'),
@@ -96,7 +97,7 @@ function hook_toolbar() {
     'tab' => array(
       '#type' => 'link',
       '#title' => t('Shopping cart'),
-      '#href' => '/cart',
+      '#url' => Url::fromRoute('cart'),
       '#options' => array(
         'html' => FALSE,
         'attributes' => array(
@@ -131,7 +132,7 @@ function hook_toolbar() {
       '#theme' => 'user_message_toolbar_tab',
       '#theme_wrappers' => array(),
       '#title' => t('Messages'),
-      '#href' => '/user/messages',
+      '#url' => Url::fromRoute('user.message'),
       '#options' => array(
         'attributes' => array(
           'title' => t('Messages'),
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 815d1cf..87cd72f 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -13,6 +13,7 @@
 use Drupal\Component\Datetime\DateTimePlus;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Url;
 use Drupal\user\RoleInterface;
 use Drupal\user\UserInterface;
 
@@ -95,7 +96,7 @@ function toolbar_element_info() {
     'tab' => array(
       '#type' => 'link',
       '#title' => NULL,
-      '#href' => '',
+      '#url' => Url::fromRoute('<front>'),
     ),
   );
   return $elements;
@@ -180,7 +181,7 @@ function toolbar_toolbar() {
     'tab' => array(
       '#type' => 'link',
       '#title' => t('Back to site'),
-      '#href' => '<front>',
+      '#url' => Url::fromRoute('<front>'),
       '#attributes' => array(
         'title' => t('Return to site content'),
         'class' => array('toolbar-icon', 'toolbar-icon-escape-admin'),
@@ -219,7 +220,7 @@ function toolbar_toolbar() {
     'tab' => array(
       '#type' => 'link',
       '#title' => t('Manage'),
-      '#href' => 'admin',
+      '#url' => Url::fromRoute('system.admin'),
       '#attributes' => array(
         'title' => t('Admin menu'),
         'class' => array('toolbar-icon', 'toolbar-icon-menu'),
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 82aca31..a5c99e1 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1450,7 +1450,7 @@ function user_toolbar() {
     $links = array(
       'account' => array(
         'title' => t('View profile'),
-        'href' => 'user',
+        'url' => Url::fromRoute('user.page'),
         'html' => TRUE,
         'attributes' => array(
           'title' => t('User account'),
@@ -1458,7 +1458,7 @@ function user_toolbar() {
       ),
       'account_edit' => array(
         'title' => t('Edit profile'),
-        'href' => 'user/' . $user->id() . '/edit',
+        'url' => Url::fromRoute('entity.user.edit_form', ['user' => $user->id()]),
         'html' => TRUE,
         'attributes' => array(
           'title' => t('Edit user account'),
@@ -1466,7 +1466,7 @@ function user_toolbar() {
       ),
       'logout' => array(
         'title' => t('Log out'),
-        'href' => 'user/logout',
+        'url' => Url::fromRoute('user.logout'),
       ),
     );
   }
@@ -1474,7 +1474,7 @@ function user_toolbar() {
      $links = array(
       'login' => array(
         'title' => t('Log in'),
-        'href' => 'user',
+        'url' => Url::fromRoute('user.page'),
       ),
     );
   }
@@ -1484,7 +1484,7 @@ function user_toolbar() {
     'tab' => array(
       '#type' => 'link',
       '#title' => $user->getUsername(),
-      '#href' => 'user',
+      '#url' => Url::fromRoute('user.page'),
       '#attributes' => array(
         'title' => t('My account'),
         'class' => array('toolbar-icon', 'toolbar-icon-user'),
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index f370bea..d411e98 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -1042,7 +1042,7 @@ public function optionLink($text, $section, $class = '', $title = '') {
       $title = $text;
     }
 
-    return \Drupal::l($text, new Url('views_ui.form_display', ['js' => 'nojs', 'view' => $this->view->storage->id(), 'display_id' => $this->display['id'], 'type' => $section], array('attributes' => array('class' => array('views-ajax-link', $class), 'title' => $title, 'id' => drupal_html_id('views-' . $this->display['id'] . '-' . $section)), 'html' => TRUE)));
+    return \Drupal::l($text, new Url('views_ui.form_display', ['view' => $this->view->storage->id(), 'display_id' => $this->display['id'], 'type' => $section], array('attributes' => array('class' => array('views-ajax-link', $class), 'title' => $title, 'id' => drupal_html_id('views-' . $this->display['id'] . '-' . $section)), 'html' => TRUE)));
   }
 
   /**
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 9ab4be0..5bd6e90 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -1045,7 +1045,7 @@ function template_preprocess_views_mini_pager(&$variables) {
     $li_previous = array(
       '#type' => 'link',
       '#title' => $tags[1],
-      '#href' => $current_path,
+      '#route_name' => '<current>',
       '#options' => array(
         'query' => pager_query_add_page($parameters, $element, $pager_page_array[$element] - 1),
         'attributes' => array(
@@ -1068,7 +1068,7 @@ function template_preprocess_views_mini_pager(&$variables) {
     $li_next = array(
       '#type' => 'link',
       '#title' => $tags[3],
-      '#href' => $current_path,
+      '#route_name' => '<current>',
       '#options' => array(
         'query' => pager_query_add_page($parameters, $element, $pager_page_array[$element] + 1),
         'attributes' => array(
diff --git a/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php b/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php
index c6e24db..bd1f24d 100644
--- a/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php
+++ b/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_ui\Form\Ajax;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 use Drupal\views_ui\ViewUI;
 
 /**
@@ -40,7 +41,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->t('Reorder displays');
     $form['#section'] = 'reorder';
     $form['#action'] = $this->url('views_ui.form_reorder_displays', [
-      'js' => 'nojs',
       'view' => $view->id(),
       'display_id' => $display_id,
     ]);
@@ -120,7 +120,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         'link' => array(
           '#type' => 'link',
           '#title' => '<span>' . $this->t('Remove') . '</span>',
-          '#href' => 'javascript:void()',
+          '#url' => Url::fromUri('javascript:void()'),
           '#options' => array(
             'html' => TRUE,
           ),
diff --git a/core/modules/views_ui/src/ViewEditForm.php b/core/modules/views_ui/src/ViewEditForm.php
index e621513..0e84df1 100644
--- a/core/modules/views_ui/src/ViewEditForm.php
+++ b/core/modules/views_ui/src/ViewEditForm.php
@@ -427,7 +427,7 @@ public function getDisplayDetails($view, $display) {
               '#type' => 'link',
               '#title' => $this->t('View !display_title', array('!display_title' => $display_title)),
               '#options' => array('alt' => array($this->t("Go to the real page for this display"))),
-              '#href' => $path,
+              '#url' => Url::fromUri("base://$path"),
               '#prefix' => '<li class="view">',
               "#suffix" => '</li>',
             );
@@ -695,12 +695,12 @@ public function renderDisplayTop(ViewUI $view) {
       '#links' => array(
         'edit-details' => array(
           'title' => $this->t('Edit view name/description'),
-          'href' => "admin/structure/views/nojs/edit-details/{$view->id()}/$display_id",
+          'url' => Url::fromRoute('views_ui.form_edit_details', ['view' => $view->id(), 'display_id' => $display_id]),
           'attributes' => array('class' => array('views-ajax-link')),
         ),
         'analyze' => array(
           'title' => $this->t('Analyze view'),
-          'href' => "admin/structure/views/nojs/analyze/{$view->id()}/$display_id",
+          'url' => Url::fromRoute('views_ui.form_analyze', ['view' => $view->id(), 'display_id' => $display_id]),
           'attributes' => array('class' => array('views-ajax-link')),
         ),
         'duplicate' => array(
@@ -708,7 +708,7 @@ public function renderDisplayTop(ViewUI $view) {
         ) + $view->urlInfo('duplicate-form')->toArray(),
         'reorder' => array(
           'title' => $this->t('Reorder displays'),
-          'href' => "admin/structure/views/nojs/reorder-displays/{$view->id()}/$display_id",
+          'url' => Url::fromRoute('views_ui.form_reorder_displays', ['view' => $view->id(), 'display_id' => $display_id]),
           'attributes' => array('class' => array('views-ajax-link')),
         ),
       ),
@@ -734,7 +734,7 @@ public function renderDisplayTop(ViewUI $view) {
       else {
         $element['extra_actions']['#links']['delete'] = array(
           'title' => $this->t('Delete view'),
-          'href' => "admin/structure/views/view/{$view->id()}/delete",
+          'url' => $view->urlInfo('delete-form'),
         );
       }
     }
@@ -944,7 +944,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
 
     $build['#name'] = $build['#title'] = $types[$type]['title'];
 
-    $rearrange_url = "admin/structure/views/nojs/rearrange/{$view->id()}/{$display['id']}/$type";
+    $rearrange_url = Url::fromRoute('views_ui.form_rearrange', ['view' => $view->id(), 'display_id' => $display['id'], 'type' => $type]);
     $class = 'icon compact rearrange';
 
     // Different types now have different rearrange forms, so we use this switch
@@ -953,7 +953,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
       case 'filter':
         // The rearrange form for filters contains the and/or UI, so override
         // the used path.
-        $rearrange_url = "admin/structure/views/nojs/rearrange-filter/{$view->id()}/{$display['id']}";
+        $rearrange_url = Url::fromRoute('views_ui.form_rearrange_filter', ['view' => $view->id(), 'display_id' => $display['id']]);
         // TODO: Add another class to have another symbol for filter rearrange.
         $class = 'icon compact rearrange';
         break;
@@ -993,7 +993,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
 
     $actions['add'] = array(
       'title' => $add_text,
-      'href' => "admin/structure/views/nojs/add-handler/{$view->id()}/{$display['id']}/$type",
+      'url' => Url::fromRoute('views_ui.form_add_handler', ['view' => $view->id(), 'display_id' => $display['id'], 'type' => $type]),
       'attributes' => array('class' => array('icon compact add', 'views-ajax-link'), 'id' => 'views-add-' . $type),
       'html' => TRUE,
     );
@@ -1003,7 +1003,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
 
       $actions['rearrange'] = array(
         'title' => $rearrange_text,
-        'href' => $rearrange_url,
+        'url' => $rearrange_url,
         'attributes' => array('class' => array($class, 'views-ajax-link'), 'id' => 'views-rearrange-' . $type),
         'html' => TRUE,
       );
@@ -1062,7 +1062,6 @@ public function getFormBucket(ViewUI $view, $type, $display) {
         $build['fields'][$id]['#class'][] = 'broken';
         $field_name = $handler->adminLabel();
         $build['fields'][$id]['#link'] = $this->l($field_name, new Url('views_ui.form_handler', array(
-          'js' => 'nojs',
           'view' => $view->id(),
           'display_id' => $display['id'],
           'type' => $type,
@@ -1085,7 +1084,6 @@ public function getFormBucket(ViewUI $view, $type, $display) {
         $link_text .= ' [' . $this->t('hidden') . ']';
       }
       $build['fields'][$id]['#link'] = $this->l($link_text, new Url('views_ui.form_handler', array(
-        'js' => 'nojs',
         'view' => $view->id(),
         'display_id' => $display['id'],
         'type' => $type,
@@ -1095,7 +1093,6 @@ public function getFormBucket(ViewUI $view, $type, $display) {
 
       if ($executable->display_handler->useGroupBy() && $handler->usesGroupBy()) {
         $build['fields'][$id]['#settings_links'][] = $this->l('<span class="label">' . $this->t('Aggregation settings') . '</span>', new Url('views_ui.form_handler_group', array(
-          'js' => 'nojs',
           'view' => $view->id(),
           'display_id' => $display['id'],
           'type' => $type,
@@ -1105,7 +1102,6 @@ public function getFormBucket(ViewUI $view, $type, $display) {
 
       if ($handler->hasExtraOptions()) {
         $build['fields'][$id]['#settings_links'][] = $this->l('<span class="label">' . $this->t('Settings') . '</span>', new Url('views_ui.form_handler_extra', array(
-          'js' => 'nojs',
           'view' => $view->id(),
           'display_id' => $display['id'],
           'type' => $type,
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 3960294..073332e 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Url;
 use Drupal\views\Views;
 use Drupal\views\ViewExecutable;
 use Drupal\views\ViewStorageInterface;
@@ -180,13 +181,13 @@ function views_ui_view_preview_section_handler_links(ViewExecutable $view, $type
     $field_name = $handler->adminLabel(TRUE);
     $links[$type . '-edit-' . $id] = array(
       'title' => t('Edit @section', array('@section' => $field_name)),
-      'href' => "admin/structure/views/nojs/handler/{$view->storage->id()}/{$display['id']}/$type/$id",
+      'url' => Url::fromRoute('views_ui.form_handler', ['view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type, 'id' => $id]),
       'attributes' => array('class' => array('views-ajax-link')),
     );
   }
   $links[$type . '-add'] = array(
     'title' => t('Add new'),
-    'href' => "admin/structure/views/nojs/add-handler/{$view->storage->id()}/{$display['id']}/$type",
+    'url' => Url::fromRoute('views_ui.form_add_handler', ['view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type]),
     'attributes' => array('class' => array('views-ajax-link')),
   );
 
@@ -201,7 +202,7 @@ function views_ui_view_preview_section_display_category_links(ViewExecutable $vi
   $links = array(
     $type . '-edit' => array(
       'title' => t('Edit @section', array('@section' => $title)),
-      'href' => "admin/structure/views/nojs/display/{$view->storage->id()}/{$display['id']}/$type",
+      'url' => Url::fromRoute('views_ui.form_display', ['view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type]),
       'attributes' => array('class' => array('views-ajax-link')),
     ),
   );
diff --git a/core/modules/views_ui/views_ui.routing.yml b/core/modules/views_ui/views_ui.routing.yml
index 9a36472..c81ada4 100644
--- a/core/modules/views_ui/views_ui.routing.yml
+++ b/core/modules/views_ui/views_ui.routing.yml
@@ -142,6 +142,7 @@ views_ui.form_add_handler:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\AddHandler::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -155,6 +156,7 @@ views_ui.form_edit_details:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\EditDetails::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -168,6 +170,7 @@ views_ui.form_reorder_displays:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\ReorderDisplays::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -181,6 +184,7 @@ views_ui.form_analyze:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\Analyze::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -194,6 +198,7 @@ views_ui.form_rearrange:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\Rearrange::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -207,6 +212,7 @@ views_ui.form_rearrange_filter:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\RearrangeFilter::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -220,6 +226,7 @@ views_ui.form_display:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\Display::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -233,6 +240,7 @@ views_ui.form_handler:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\ConfigHandler::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -246,6 +254,7 @@ views_ui.form_handler_extra:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\ConfigHandlerExtra::getForm'
+    js: 'nojs'
   requirements:
     _entity_access: view.update
     js: 'nojs|ajax'
@@ -259,6 +268,7 @@ views_ui.form_handler_group:
         type: entity:view
   defaults:
     _content: '\Drupal\views_ui\Form\Ajax\ConfigHandlerGroup::getForm'
+    js: 'nojs'
     form_state: NULL
   requirements:
     _entity_access: view.update
diff --git a/core/modules/views_ui/views_ui.theme.inc b/core/modules/views_ui/views_ui.theme.inc
index 80f2f45..4528490 100644
--- a/core/modules/views_ui/views_ui.theme.inc
+++ b/core/modules/views_ui/views_ui.theme.inc
@@ -9,6 +9,7 @@
 use Drupal\Core\Form\FormState;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Url;
 
 /**
  * Prepares variables for Views UI display tab setting templates.
@@ -283,7 +284,7 @@ function template_preprocess_views_ui_rearrange_filter_form(&$variables) {
 
         $remove_link = array(
           '#type' => 'link',
-          '#href' => '',
+          '#url' => Url::fromRoute('<none>'),
           '#title' => '<span>' . t('Remove') . '</span>',
           '#weight' => '1',
           '#options' => array(
diff --git a/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php b/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php
index 176d5b4..b49c150 100644
--- a/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/ConfirmFormHelperTest.php
@@ -47,7 +47,7 @@ public function testCancelLinkRoute() {
       ->method('getCancelUrl')
       ->will($this->returnValue($cancel_route));
     $link = ConfirmFormHelper::buildCancelLink($form, new Request());
-    $this->assertSame($route_name, $link['#route_name']);
+    $this->assertEquals(Url::fromRoute($route_name), $link['#url']);
   }
 
   /**
@@ -65,14 +65,13 @@ public function testCancelLinkRouteWithParams() {
         'absolute' => TRUE,
       ),
     );
+    $expected = Url::fromRoute($cancel_route['route_name'], $cancel_route['route_parameters'], $cancel_route['options']);
     $form = $this->getMock('Drupal\Core\Form\ConfirmFormInterface');
     $form->expects($this->any())
       ->method('getCancelUrl')
-      ->will($this->returnValue(new Url($cancel_route['route_name'], $cancel_route['route_parameters'], $cancel_route['options'])));
+      ->will($this->returnValue($expected));
     $link = ConfirmFormHelper::buildCancelLink($form, new Request());
-    $this->assertSame($cancel_route['route_name'], $link['#route_name']);
-    $this->assertSame($cancel_route['route_parameters'], $link['#route_parameters']);
-    $this->assertSame($cancel_route['options'], $link['#options']);
+    $this->assertEquals($expected, $link['#url']);
   }
 
   /**
@@ -94,9 +93,7 @@ public function testCancelLinkRouteWithUrl() {
       ->method('getCancelUrl')
       ->will($this->returnValue($cancel_route));
     $link = ConfirmFormHelper::buildCancelLink($form, new Request());
-    $this->assertSame($cancel_route->getRouteName(), $link['#route_name']);
-    $this->assertSame($cancel_route->getRouteParameters(), $link['#route_parameters']);
-    $this->assertSame($cancel_route->getOptions(), $link['#options']);
+    $this->assertSame($cancel_route, $link['#url']);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index cf0496f..75c4768 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -350,9 +350,7 @@ public function testAccess($access) {
    */
   public function testRenderAccess($access) {
     $element = array(
-      '#route_name' => 'entity.node.canonical',
-      '#route_parameters' => ['node' => 3],
-      '#options' => [],
+      '#url' => Url::fromRoute('entity.node.canonical', ['node' => 3]),
     );
     $this->container->set('current_user', $this->getMock('Drupal\Core\Session\AccountInterface'));
     $this->container->set('access_manager', $this->getMockAccessManager($access));
