diff --git a/core/modules/user/lib/Drupal/user/UserRouteController.php b/core/modules/user/lib/Drupal/user/UserRouteController.php
index cf3b50e..21b70bb 100644
--- a/core/modules/user/lib/Drupal/user/UserRouteController.php
+++ b/core/modules/user/lib/Drupal/user/UserRouteController.php
@@ -8,6 +8,7 @@
 namespace Drupal\user;
 
 use Symfony\Component\DependencyInjection\ContainerAware;
+use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
  * Returns responses for User module routes.
@@ -25,4 +26,46 @@ public function register() {
     return entity_get_form($account, 'register');
   }
 
+  /**
+   * Returns response for the user autocompletion.
+   *
+   * @param bool $include_anonymous
+   *   (optional) TRUE if the the name used to indicate anonymous users (e.g.
+   *   "Anonymous") should be autocompleted. Defaults to FALSE.
+   *
+   * @return \Symfony\Component\HttpFoundation\JsonResponse
+   *   A JSON response containing the autocomplete suggestions for existing users.
+   */
+  public function autocompleteUser($include_anonymous = FALSE) {
+    $matches = array();
+    $query = $this->container->get('request')->query;
+    if ($string = $query->get('q')) {
+      if ($include_anonymous) {
+        $anonymous_name = $this->container->get('config.factory')->get('user.settings')->get('anonymous');
+        // Allow autocompletion for the anonymous user.
+        if (stripos($anonymous_name, $string) !== FALSE) {
+          $matches[$anonymous_name] = check_plain($anonymous_name);
+        }
+      }
+      $result = $this->container->get('database')->select('users')->fields('users', array('name'))->condition('name', db_like($string) . '%', 'LIKE')->range(0, 10)->execute();
+      foreach ($result as $account) {
+        $matches[$account->name] = check_plain($account->name);
+      }
+    }
+
+    return new JsonResponse($matches);
+  }
+
+  /**
+   * Returns response for the user autocompletion with the anonymous user.
+   *
+   * @return \Symfony\Component\HttpFoundation\JsonResponse
+   *   A JSON response containing the autocomplete suggestions for existing users.
+   *
+   * @see \Drupal\user\UserRouteController\autocompleteUser
+   */
+  public function autocompleteUserAnonymous() {
+    return $this->autocompleteUser(TRUE);
+  }
+
 }
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 4500c9b..3857809 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -865,24 +865,6 @@ function user_register_access() {
  * Implements hook_menu().
  */
 function user_menu() {
-  $items['user/autocomplete'] = array(
-    'title' => 'User autocomplete',
-    'page callback' => 'user_autocomplete',
-    'access callback' => 'user_access',
-    'access arguments' => array('access user profiles'),
-    'type' => MENU_CALLBACK,
-    'file' => 'user.pages.inc',
-  );
-
-  $items['user/autocomplete/anonymous'] = array(
-    'title' => 'User autocomplete including anonymous',
-    'page callback' => 'user_autocomplete',
-    'page arguments' => array(TRUE),
-    'access callback' => 'user_access',
-    'access arguments' => array('access user profiles'),
-    'type' => MENU_CALLBACK,
-    'file' => 'user.pages.inc',
-  );
   // Registration and login pages.
   $items['user'] = array(
     'title' => 'User account',
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index 5a872ab..6559313 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -12,39 +12,6 @@
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 
 /**
- * Menu callback for user autocompletion.
- *
- * Like other autocomplete functions, this function inspects the 'q' query
- * parameter for the string to use to search for suggestions.
- *
- * @param bool $include_anonymous
- *   (optional) TRUE if the the name used to indicate anonymous users (e.g.
- *   "Anonymous") should be autocompleted. Defaults to FALSE.
- *
- * @return \Symfony\Component\HttpFoundation\JsonResponse
- *   A JSON response containing the autocomplete suggestions for existing users.
- */
-function user_autocomplete($include_anonymous = FALSE) {
-  $matches = array();
-  $query = drupal_container()->get('request')->query;
-  if ($string = $query->get('q')) {
-    if ($include_anonymous) {
-      $anonymous_name = config('user.settings')->get('anonymous');
-      // Allow autocompletion for the anonymous user.
-      if (stripos($anonymous_name, $string) !== FALSE) {
-        $matches[$anonymous_name] = check_plain($anonymous_name);
-      }
-    }
-    $result = db_select('users')->fields('users', array('name'))->condition('name', db_like($string) . '%', 'LIKE')->range(0, 10)->execute();
-    foreach ($result as $account) {
-      $matches[$account->name] = check_plain($account->name);
-    }
-  }
-
-  return new JsonResponse($matches);
-}
-
-/**
  * Form builder; Request a password reset.
  *
  * @ingroup forms
diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml
index c3a05d7..2c3cc14 100644
--- a/core/modules/user/user.routing.yml
+++ b/core/modules/user/user.routing.yml
@@ -4,3 +4,15 @@ user_register:
     _content: '\Drupal\user\UserRouteController::register'
   requirements:
     _access_user_register: 'TRUE'
+user_autocomplete:
+  pattern: '/user/autocomplete'
+  defaults:
+    _content: '\Drupal\user\UserRouteController::autocompleteUser'
+  requirements:
+    _permission: 'access user profiles'
+user_autocomplete_anonymous:
+  pattern: '/user/autocomplete/anonymous'
+  defaults:
+    _content: '\Drupal\user\UserRouteController::autocompleteUserAnonymous'
+  requirements:
+    _permission: 'access user profiles'
