diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc
index 3ee1eaa..325ff88 100644
--- a/core/modules/field_ui/field_ui.admin.inc
+++ b/core/modules/field_ui/field_ui.admin.inc
@@ -6,58 +6,6 @@
  */
 
 /**
- * Page callback: Lists all defined fields for quick reference.
- *
- * @see field_ui_menu()
- */
-function field_ui_fields_list() {
-  $instances = field_info_instances();
-  $field_types = field_info_field_types();
-  $bundles = entity_get_bundles();
-  $entity_manager = Drupal::entityManager();
-
-  $modules = system_rebuild_module_data();
-
-  $header = array(
-    t('Field name'),
-    array('data' => t('Field type'), 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)),
-    t('Used in'),
-  );
-  $rows = array();
-  foreach ($instances as $entity_type => $type_bundles) {
-    foreach ($type_bundles as $bundle => $bundle_instances) {
-      foreach ($bundle_instances as $field_name => $instance) {
-        $field = field_info_field($field_name);
-
-        // Initialize the row if we encounter the field for the first time.
-        if (!isset($rows[$field_name])) {
-          $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
-          $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
-          $module_name = $field_types[$field['type']]['module'];
-          $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
-        }
-
-        // Add the current instance.
-        $admin_path = $entity_manager->getAdminPath($entity_type, $bundle);
-        $rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label'];
-      }
-    }
-  }
-  foreach ($rows as $field_name => $cell) {
-    $rows[$field_name]['data'][2] = implode(', ', $cell['data'][2]);
-  }
-  if (empty($rows)) {
-    $output = t('No fields have been defined yet.');
-  }
-  else {
-    // Sort rows by field name.
-    ksort($rows);
-    $output = theme('table', array('header' => $header, 'rows' => $rows));
-  }
-  return $output;
-}
-
-/**
  * Displays a message listing the inactive fields of a given bundle.
  */
 function field_ui_inactive_message($entity_type, $bundle) {
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index cce8734..cd51e62 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -56,8 +56,7 @@ function field_ui_menu() {
   $items['admin/reports/fields'] = array(
     'title' => 'Field list',
     'description' => 'Overview of fields on all entity types.',
-    'page callback' => 'field_ui_fields_list',
-    'access arguments' => array('administer content types'),
+    'route_name' => 'field_list',
     'type' => MENU_NORMAL_ITEM,
     'file' => 'field_ui.admin.inc',
   );
diff --git a/core/modules/field_ui/field_ui.routing.yml b/core/modules/field_ui/field_ui.routing.yml
new file mode 100644
index 0000000..e432c0e
--- /dev/null
+++ b/core/modules/field_ui/field_ui.routing.yml
@@ -0,0 +1,6 @@
+field_list:
+  pattern: 'admin/reports/fields'
+  defaults:
+    _content: '\Drupal\field_ui\Controller\FieldUIController::fieldsList'
+  requirements:
+    _permission: 'administer content types'
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Controller/FieldUIController.php b/core/modules/field_ui/lib/Drupal/field_ui/Controller/FieldUIController.php
new file mode 100644
index 0000000..81b1518
--- /dev/null
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Controller/FieldUIController.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field_ui\Controller;
+ */
+
+namespace Drupal\field_ui\Controller;
+
+use Drupal\Core\ControllerInterface;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\field\FieldInfo;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Controller routines for field ui routes.
+ */
+class FieldUIController implements ControllerInterface {
+
+  /**
+   * The entity manager to use to load unchanged entities.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * Provides field and instance definitions.
+   *
+   * @var \Drupal\field\FieldInfo
+   */
+  protected $fieldInfo;
+
+  /**
+   * Constructs a FieldTranslationSynchronizer object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entityManager
+   *   The entity manager.
+   */
+  public function __construct(EntityManager $entityManager, FieldInfo $fieldInfo) {
+    $this->entityManager = $entityManager;
+    $this->fieldInfo = $fieldInfo;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.entity'),
+      $container->get('field.info')
+    );
+  }
+
+  /**
+   * Returns an administrative overview of all fields for quick overview.
+   *
+   * @return string
+   *   A HTML-formatted string with the administrative page content.
+   */
+  public function fieldsList() {
+    $instances = $this->fieldInfo->getInstances();
+    $field_types = field_info_field_types();
+    $bundles = entity_get_bundles();
+    $entity_manager = $this->entityManager;
+
+    $modules = system_rebuild_module_data();
+
+    $header = array(
+      t('Field name'),
+      array('data' => t('Field type'), 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)),
+      t('Used in'),
+    );
+    $rows = array();
+    foreach ($instances as $entity_type => $type_bundles) {
+      foreach ($type_bundles as $bundle => $bundle_instances) {
+        foreach ($bundle_instances as $field_name => $instance) {
+          $field = field_info_field($field_name);
+
+          // Initialize the row if we encounter the field for the first time.
+          if (!isset($rows[$field_name])) {
+            $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
+            $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
+            $module_name = $field_types[$field['type']]['module'];
+            $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
+          }
+
+          // Add the current instance.
+          $admin_path = $entity_manager->getAdminPath($entity_type, $bundle);
+          $rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label'];
+        }
+      }
+    }
+    foreach ($rows as $field_name => $cell) {
+      $rows[$field_name]['data'][2] = implode(', ', $cell['data'][2]);
+    }
+    if (empty($rows)) {
+      $output = t('No fields have been defined yet.');
+    }
+    else {
+      // Sort rows by field name.
+      ksort($rows);
+      $output = theme('table', array('header' => $header, 'rows' => $rows));
+    }
+    return $output;
+  }
+
+}
