diff --git a/core/modules/layout/layout.admin.inc b/core/modules/layout/layout.admin.inc
deleted file mode 100644
index 63fe122..0000000
--- a/core/modules/layout/layout.admin.inc
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/**
- * @file
- * Administration functions for layouts.
- */
-
-/**
- * Page callback: Demonstrates a layout template.
- *
- * @param string $key
- *   The key of the page layout being requested.
- *
- * @return array
- *   An array as expected by drupal_render().
- *
- * @see layout_menu()
- */
-function layout_page_view($key) {
-  $layout = Drupal::service('plugin.manager.layout')->getDefinition($key);
-  drupal_set_title(t('View template %name', array('%name' => $layout['title'])), PASS_THROUGH);
-
-  // Render the layout in an admin context with region demonstrations.
-  $instance = Drupal::service('plugin.manager.layout')->createInstance($key, array());
-  $regions = $instance->getRegions();
-  foreach ($regions as $region => $info) {
-    $regions[$region] = '<div class="layout-region-demonstration">' . check_plain($info['label']) . '</div>';
-  }
-  $build['demonstration'] = array(
-    '#markup' => $instance->renderLayout(TRUE, $regions),
-  );
-  $build['#attached']['css'][] = drupal_get_path('module', 'layout') . '/css/layout.admin.css';
-  return $build;
-}
diff --git a/core/modules/layout/layout.module b/core/modules/layout/layout.module
index 8c0f29d..3d91526 100644
--- a/core/modules/layout/layout.module
+++ b/core/modules/layout/layout.module
@@ -16,30 +16,12 @@ function layout_menu() {
   );
   $items['admin/structure/templates/manage/%'] = array(
     'title' => 'View template',
-    'page callback' => 'layout_page_view',
-    'page arguments' => array(4),
-    'access callback' => 'layout_user_access',
-    'access arguments' => array(4),
-    'file' => 'layout.admin.inc',
+    'route_name' => 'layout_page_view',
   );
   return $items;
 }
 
 /**
- * Access callback: Checks the existence of a layout.
- *
- * @param string $key
- *   The key of the page layout being requested.
- *
- * @return bool
- *   TRUE if the current user can access page layout menu items; FALSE
- *   otherwise.
- */
-function layout_user_access($key) {
-  return (user_access('administer layouts') && Drupal::service('plugin.manager.layout')->getDefinition($key));
-}
-
-/**
  * Implements hook_permission().
  */
 function layout_permission() {
diff --git a/core/modules/layout/layout.routing.yml b/core/modules/layout/layout.routing.yml
index d1cd540..f7a1829 100644
--- a/core/modules/layout/layout.routing.yml
+++ b/core/modules/layout/layout.routing.yml
@@ -4,3 +4,13 @@ layout_page_list:
     _content: '\Drupal\layout\Controller\LayoutController::layoutPageList'
   requirements:
     _permission: 'administer layouts'
+
+layout_page_view:
+  pattern: '/admin/structure/templates/manage/{key}'
+  defaults:
+    _content: '\Drupal\layout\Controller\LayoutController::layoutPageView'
+  options:
+    _access_mode: 'ALL'
+  requirements:
+    _permission: 'administer layouts'
+    _access_layout_user: 'TRUE'
diff --git a/core/modules/layout/layout.services.yml b/core/modules/layout/layout.services.yml
index d387b77..c882dd9 100644
--- a/core/modules/layout/layout.services.yml
+++ b/core/modules/layout/layout.services.yml
@@ -2,3 +2,8 @@ services:
   plugin.manager.layout:
     class: Drupal\layout\Plugin\Type\LayoutManager
     arguments: ['@container.namespaces']
+  access_check.layout:
+    class: Drupal\layout\Access\LayoutAccessCheck
+    arguments: ['@plugin.manager.layout']
+    tags:
+      - { name: access_check }
diff --git a/core/modules/layout/lib/Drupal/layout/Access/LayoutAccessCheck.php b/core/modules/layout/lib/Drupal/layout/Access/LayoutAccessCheck.php
new file mode 100644
index 0000000..2c76dba
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Access/LayoutAccessCheck.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\layout\Access\LayoutAccessCheck.
+ */
+
+namespace Drupal\layout\Access;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Access\StaticAccessCheckInterface;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Checks layout access.
+ */
+class LayoutAccessCheck implements StaticAccessCheckInterface {
+
+  /**
+   * The layout manager.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $layoutManager;
+
+  /**
+   * Constructs a LayoutAccessCheck object.
+   *
+   * @param \Drupal\Component\Plugin\PluginManagerInterface $layout_manager
+   *   The layout manager.
+   */
+  public function __construct(PluginManagerInterface $layout_manager) {
+    $this->layoutManager = $layout_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function appliesTo() {
+    return '_access_layout_user';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(Route $route, Request $request) {
+    return $this->layoutManager->getDefinition($request->attributes->get('key')) ? static::ALLOW : static::DENY;
+  }
+
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Controller/LayoutController.php b/core/modules/layout/lib/Drupal/layout/Controller/LayoutController.php
index b9ad7f9..246b628 100644
--- a/core/modules/layout/lib/Drupal/layout/Controller/LayoutController.php
+++ b/core/modules/layout/lib/Drupal/layout/Controller/LayoutController.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Contains \Drupal\layout\Controller\LayoutController.
@@ -6,6 +7,7 @@
 
 namespace Drupal\layout\Controller;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Controller\ControllerInterface;
 use Drupal\layout\Plugin\Type\LayoutManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -76,4 +78,31 @@ public function layoutPageList() {
     t('module');
     t('theme');
   }
+
+  /**
+   * Demonstrates a layout template.
+   *
+   * @param string $key
+   *   The key of the page layout being requested.
+   *
+   * @return array
+   *   An array as expected by drupal_render().
+   */
+  public function layoutPageView($key) {
+    $layout = $this->layoutManager->getDefinition($key);
+    drupal_set_title(t('View template %name', array('%name' => $layout['title'])), PASS_THROUGH);
+
+    // Render the layout in an admin context with region demonstrations.
+    $instance = $this->layoutManager->createInstance($key, array());
+    $regions = $instance->getRegions();
+    foreach ($regions as $region => $info) {
+      $regions[$region] = '<div class="layout-region-demonstration">' . String::checkPlain($info['label']) . '</div>';
+    }
+    $build['demonstration']['#markup'] = $instance->renderLayout(TRUE, $regions);
+
+    // @todo Convert layout.admin.css to a library.
+    $build['#attached']['css'][] = drupal_get_path('module', 'layout') . '/layout.admin.css';
+    return $build;
+  }
+
 }
