diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index e309ec7..59c5553 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -15,6 +15,7 @@
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Drupal\comment\Plugin\Core\Entity\Comment;
 
 /**
  * Comment is awaiting approval.
@@ -76,8 +77,6 @@
  */
 const COMMENT_NODE_OPEN = 2;
 
-use Drupal\comment\Plugin\Core\Entity\Comment;
-
 /**
  * Implements hook_help().
  */
@@ -221,10 +220,7 @@ function comment_menu() {
   );
   $items['comment/%comment'] = array(
     'title' => 'Comment permalink',
-    'page callback' => 'comment_permalink',
-    'page arguments' => array(1),
-    'access callback' => 'entity_page_access',
-    'access arguments' => array(1, 'view'),
+    'route_name' => 'comment_permalink',
   );
   $items['comment/%comment/view'] = array(
     'title' => 'View comment',
@@ -408,39 +404,6 @@ function comment_permission() {
 }
 
 /**
- * Redirects comment links to the correct page depending on comment settings.
- *
- * Since comments are paged there is no way to guarantee which page a comment
- * appears on. Comment paging and threading settings may be changed at any time.
- * With threaded comments, an individual comment may move between pages as
- * comments can be added either before or after it in the overall discussion.
- * Therefore we use a central routing function for comment links, which
- * calculates the page number based on current comment settings and returns
- * the full comment view with the pager set dynamically.
- *
- * @param \Drupal\comment\Plugin\Core\Entity\Comment $comment
- *   A comment entity.
- *
- * @return
- *   The comment listing set to the page on which the comment appears.
- */
-function comment_permalink(Comment $comment) {
-  if ($node = $comment->nid->entity) {
-    // Find the current display page for this comment.
-    $page = comment_get_display_page($comment->id(), $node->type);
-
-    // @todo: Cleaner sub request handling.
-    $request = drupal_container()->get('request');
-    $subrequest = Request::create('/node/' . $node->nid, 'GET', $request->query->all(), $request->cookies->all(), array(), $request->server->all());
-    $subrequest->query->set('page', $page);
-    // @todo: Convert the pager to use the request object.
-    $_GET['page'] = $page;
-    return drupal_container()->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
-  }
-  throw new NotFoundHttpException();
-}
-
-/**
  * Finds the most recent comments that are available to the current user.
  *
  * @param integer $number
diff --git a/core/modules/comment/comment.routing.yml b/core/modules/comment/comment.routing.yml
index 6f786dd..a7b4fe2 100644
--- a/core/modules/comment/comment.routing.yml
+++ b/core/modules/comment/comment.routing.yml
@@ -4,4 +4,9 @@ comment_edit_page:
         _entity_form: comment.default
     requirements:
         _entity_access: comment.update
-
+comment_permalink:
+  pattern: '/comment/{comment}'
+  defaults:
+    _controller: '\Drupal\comment\Controller\CommentController::commentPermalink'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
new file mode 100644
index 0000000..3265cfd
--- /dev/null
+++ b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Controller\CommentController.
+ */
+
+namespace Drupal\comment\Controller;
+
+use Drupal\Core\Controller\ControllerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\comment\Plugin\Core\Entity\Comment;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * Controller methods for comment routes.
+ */
+class CommentController implements ControllerInterface {
+
+  /**
+   * The HTTP kernel.
+   *
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+   */
+  protected $httpKernel;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static($container->get('http_kernel'));
+  }
+
+  /**
+   * Constructs a new CommentController instance
+   *
+   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel
+   *   HTTP kernel to handle requests.
+   */
+  public function __construct(HttpKernelInterface $httpKernel) {
+    $this->httpKernel = $httpKernel;
+  }
+
+  /**
+   * Redirects comment links to the correct page depending on comment settings.
+   *
+   * Since comments are paged there is no way to guarantee which page a comment
+   * appears on. Comment paging and threading settings may be changed at any
+   * time. With threaded comments, an individual comment may move between pages
+   * as comments can be added either before or after it in the overall
+   * discussion. Therefore we use a central routing function for comment links,
+   * which calculates the page number based on current comment settings and
+   * returns the full comment view with the pager set dynamically.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request of the page.
+   * @param \Drupal\comment\Plugin\Core\Entity\Comment $comment
+   *   A comment entity.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   * @return \Symfony\Component\HttpFoundation\Response
+   *   The comment listing set to the page on which the comment appears.
+   */
+  public function commentPermalink(Request $request, Comment $comment) {
+    if ($node = $comment->nid->entity) {
+      // Check access permissions for the node entity.
+      if (!$node->access('view')) {
+        throw new AccessDeniedHttpException();
+      }
+      // Find the current display page for this comment.
+      $page = comment_get_display_page($comment->id(), $node->type);
+      // @todo: Cleaner sub request handling.
+      $redirect_request = Request::create('/node/' . $node->nid, 'GET', $request->query->all(), $request->cookies->all(), array(), $request->server->all());
+      $redirect_request->query->set('page', $page);
+      // @todo: Convert the pager to use the request object.
+      $_GET['page'] = $page;
+      return $this->httpKernel->handle($redirect_request, HttpKernelInterface::SUB_REQUEST);
+    }
+    throw new NotFoundHttpException();
+  }
+
+}
