diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index 64aa6bd..1f9cbc4 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -32,6 +32,23 @@ function comment_install() {
 }
 
 /**
+ * Implements hook_modules_installed().
+ */
+function comment_modules_installed($modules) {
+  // Book was just installed, or Comment was just installed while Book
+  // is (already/newly) installed too.
+  if (in_array('book', $modules)
+      || (in_array('comment', $modules) && \Drupal::moduleHandler()->moduleExists('book'))) {
+    foreach (\Drupal::service('comment.manager')->getFields('node') as $field_name => $detail) {
+      foreach ($detail['bundles'] as $bundle) {
+        $display = entity_get_display('node', $bundle, 'print');
+        $display->removeComponent($field_name)->save();
+      }
+    }
+  }
+}
+
+/**
  * Implements hook_schema().
  */
 function comment_schema() {
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 5ab742d..45537c8 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -12,7 +12,6 @@
 
 use Drupal\comment\CommentInterface;
 use Drupal\comment\Entity\Comment;
-use Drupal\comment\CommentManagerInterface;
 use Drupal\comment\Entity\CommentType;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
@@ -203,8 +202,6 @@ function comment_node_links_alter(array &$node_links, NodeInterface $node, array
   // Comment links are only added to node entity type for backwards
   // compatibility. Should you require comment links for other entity types you
   // can do so by implementing a new field formatter.
-  // @todo Make this configurable from the formatter see
-  //   http://drupal.org/node/1901110
 
   $links = \Drupal::service('comment.link_builder')->buildCommentedEntityLinks($node, $context);
   $node_links += $links;
@@ -454,17 +451,18 @@ function comment_node_update_index(EntityInterface $node, $langcode) {
   $build = array();
 
   if ($index_comments) {
+    $node_base_defs = \Drupal::entityManager()->getFieldStorageDefinitions($node->getEntityTypeId());
     foreach (\Drupal::service('comment.manager')->getFields('node') as $field_name => $info) {
       // Skip fields that entity does not have.
       if (!$node->hasField($field_name)) {
         continue;
       }
-      $field_definition = $node->getFieldDefinition($field_name);
-      $mode = $field_definition->getSetting('default_mode');
-      $comments_per_page = $field_definition->getSetting('per_page');
       if ($node->get($field_name)->status) {
+        $comment_type = CommentType::load($node_base_defs[$field_name]->getSetting('comment_type'));
+        $display_settings = entity_get_display($node->getEntityTypeId(), $node->bundle(), 'default')
+          ->getComponent($field_name);
         $comments = \Drupal::entityManager()->getStorage('comment')
-          ->loadThread($node, $field_name, $mode, $comments_per_page);
+          ->loadThread($node, $field_name, $comment_type->getThreadingMode(), $display_settings['settings']['per_page']);
         if ($comments) {
           comment_prepare_thread($comments);
           $build[] = \Drupal::entityManager()->getViewBuilder('comment')->viewMultiple($comments);
@@ -793,7 +791,7 @@ function comment_preprocess_field(&$variables) {
   $element = $variables['element'];
   if ($element['#field_type'] == 'comment') {
     // Provide contextual information.
-    $variables['comment_display_mode'] = $element[0]['#comment_display_mode'];
+    $variables['comment_threading_mode'] = $element[0]['#comment_threading_mode'];
     $variables['comment_type'] = $element[0]['#comment_type'];
 
     // Append additional attributes (eg. RDFa) from the first field item.
diff --git a/core/modules/comment/comment.services.yml b/core/modules/comment/comment.services.yml
index 7f82f97..57d3499 100644
--- a/core/modules/comment/comment.services.yml
+++ b/core/modules/comment/comment.services.yml
@@ -21,4 +21,4 @@ services:
 
   comment.link_builder:
     class: Drupal\comment\CommentLinkBuilder
-    arguments: ['@current_user', '@comment.manager', '@module_handler', '@string_translation']
+    arguments: ['@current_user', '@entity.manager', '@comment.manager', '@module_handler', '@string_translation']
diff --git a/core/modules/comment/config/schema/comment.schema.yml b/core/modules/comment/config/schema/comment.schema.yml
index d9f5a77..416f65d 100644
--- a/core/modules/comment/config/schema/comment.schema.yml
+++ b/core/modules/comment/config/schema/comment.schema.yml
@@ -51,6 +51,9 @@ comment.type.*:
     description:
       type: text
       label: 'Description'
+    threading_mode:
+      type: integer
+      label: 'Threading'
 
 field.storage_settings.comment:
   type: mapping
@@ -87,18 +90,9 @@ field.field_settings.comment:
   type: mapping
   label: 'Comment settings'
   mapping:
-    default_mode:
-      type: integer
-      label: 'Threading'
-    per_page:
-      type: integer
-      label: 'Comments per page'
     anonymous:
       type: integer
       label: 'Mode'
-    form_location:
-      type: boolean
-      label: ' Allow comment title'
     preview:
       type: integer
       label: 'Preview comment'
diff --git a/core/modules/comment/src/CommentForm.php b/core/modules/comment/src/CommentForm.php
index 8f7368a..a56e31c 100644
--- a/core/modules/comment/src/CommentForm.php
+++ b/core/modules/comment/src/CommentForm.php
@@ -367,14 +367,23 @@ public function save(array $form, FormStateInterface $form_state) {
       else {
         drupal_set_message($this->t('Your comment has been posted.'));
       }
-      $query = array();
-      // Find the current display page for this comment.
-      $field_definition = $this->entityManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle())[$field_name];
-      $page = $this->entityManager->getStorage('comment')->getDisplayOrdinal($comment, $field_definition->getSetting('default_mode'), $field_definition->getSetting('per_page'));
-      if ($page > 0) {
-        $query['page'] = $page;
+      // Find the current display page for this comment. We link to it using
+      // the standard entity urlInfo, i.e. the full/default view mode.
+      $page_number = 0;
+      $display = $this->entityManager->getStorage('entity_view_display')
+        ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.full');
+      if (!$display) {
+        $display = $this->entityManager->getStorage('entity_view_display')
+          ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.default');
+      }
+      $formatter_options = $display ? $display->getComponent($field_name): NULL;
+      if ($formatter_options) {
+        $field_definition = $this->entityManager->getFieldStorageDefinitions($entity->getEntityTypeId())[$field_name];
+        $comment_type = $this->entityManager->getStorage('comment_type')->load($field_definition->getSetting('comment_type'));
+        $page_number = $this->entityManager->getStorage('comment')->getDisplayOrdinal($comment, $comment_type->getThreadingMode(), $formatter_options['settings']['per_page']);
       }
       // Redirect to the newly posted comment.
+      $query = $page_number ? array('page' => $page_number) : NULL;
       $uri->setOption('query', $query);
       $uri->setOption('fragment', 'comment-' . $comment->id());
     }
diff --git a/core/modules/comment/src/CommentLinkBuilder.php b/core/modules/comment/src/CommentLinkBuilder.php
index 951a69f..6c03093 100644
--- a/core/modules/comment/src/CommentLinkBuilder.php
+++ b/core/modules/comment/src/CommentLinkBuilder.php
@@ -9,16 +9,25 @@
 
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Url;
+use Symfony\Component\HttpFoundation\Request;
+
 
 /**
  * Defines a class for building markup for comment links on a commented entity.
  *
  * Comment links include 'login to post new comment', 'add new comment' etc.
+ *
+ * Note this class does not build the regular links displayed with a comment
+ * entity. (Those have a regular field formatter; see
+ * CommentViewBuilder::renderLinks() for those.) The links generated here can
+ * be added to the regular links displayed with the commentED entity. (This is
+ * done automatically for nodes by comment_node_links_alter().)
  */
 class CommentLinkBuilder implements CommentLinkBuilderInterface {
 
@@ -32,6 +41,13 @@ class CommentLinkBuilder implements CommentLinkBuilderInterface {
   protected $currentUser;
 
   /**
+   * Entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
    * Comment manager service.
    *
    * @var \Drupal\comment\CommentManagerInterface
@@ -57,8 +73,9 @@ class CommentLinkBuilder implements CommentLinkBuilderInterface {
    * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
    *   String translation service.
    */
-  public function __construct(AccountInterface $current_user, CommentManagerInterface $comment_manager, ModuleHandlerInterface $module_handler, TranslationInterface $string_translation) {
+  public function __construct(AccountInterface $current_user, EntityManagerInterface $entity_manager, CommentManagerInterface $comment_manager, ModuleHandlerInterface $module_handler, TranslationInterface $string_translation) {
     $this->currentUser = $current_user;
+    $this->entityManager = $entity_manager;
     $this->commentManager = $comment_manager;
     $this->moduleHandler = $module_handler;
     $this->stringTranslation = $string_translation;
@@ -88,7 +105,7 @@ public function buildCommentedEntityLinks(FieldableEntityInterface $entity, arra
       $commenting_status = $entity->get($field_name)->status;
       if ($commenting_status != CommentItemInterface::HIDDEN) {
         // Entity has commenting status open or closed.
-        $field_definition = $entity->getFieldDefinition($field_name);
+
         if ($view_mode == 'rss') {
           // Add a comments RSS element which is a URL to the comments of this
           // entity.
@@ -101,85 +118,116 @@ public function buildCommentedEntityLinks(FieldableEntityInterface $entity, arra
             'value' => $entity->url('canonical', $options),
           );
         }
-        elseif ($view_mode == 'teaser') {
-          // Teaser view: display the number of comments that have been posted,
-          // or a link to add new comments if the user has permission, the
-          // entity is open to new comments, and there currently are none.
-          if ($this->currentUser->hasPermission('access comments')) {
-            if (!empty($entity->get($field_name)->comment_count)) {
-              $links['comment-comments'] = array(
-                'title' => $this->formatPlural($entity->get($field_name)->comment_count, '1 comment', '@count comments'),
-                'attributes' => array('title' => $this->t('Jump to the first comment.')),
-                'fragment' => 'comments',
+        else {
+          // We create links to the first new comment using the standard entity
+          // urlInfo, i.e. the full/default view mode.
+          $display = $this->entityManager->getStorage('entity_view_display')
+            ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.full');
+          if (!$display) {
+            $display = $this->entityManager->getStorage('entity_view_display')
+              ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.default');
+          }
+          $formatter_options_full = $display
+            ? $display->getComponent($field_name): NULL;
+
+          // Add the number of comments that have been posted and a link to the
+          // first new comment, if they are displayed on 'full' mode and the
+          // user has permission. Historically this is done for teaser only.
+          if ($view_mode == 'teaser' && $formatter_options_full
+              && !empty($entity->get($field_name)->comment_count)
+              && $this->currentUser->hasPermission('access comments')) {
+            // Comments can theoretically be displayed inside a teaser, but even
+            // then we still choose to link to the 'full page' comments. These
+            // are the only ones that have a pager, i.e. have all comments
+            // reachable. (Only for 'full' mode we are sure we can reach the
+            // first new comment.)
+            $links['comment-comments'] = array(
+              'title' => $this->formatPlural($entity->get($field_name)->comment_count, '1 comment', '@count comments'),
+              'attributes' => array('title' => $this->t('Jump to the first comment.')),
+              'fragment' => 'comments',
+              'url' => $entity->urlInfo(),
+            );
+            if ($this->moduleHandler->moduleExists('history')) {
+              $links['comment-new-comments'] = array(
+                'title' => '',
                 'url' => $entity->urlInfo(),
+                'attributes' => array(
+                  'class' => 'hidden',
+                  'title' => $this->t('Jump to the first new comment.'),
+                  'data-history-node-last-comment-timestamp' => $entity->get($field_name)->last_comment_timestamp,
+                  'data-history-node-field-name' => $field_name,
+                ),
               );
-              if ($this->moduleHandler->moduleExists('history')) {
-                $links['comment-new-comments'] = array(
-                  'title' => '',
-                  'url' => Url::fromRoute('<current>'),
-                  'attributes' => array(
-                    'class' => 'hidden',
-                    'title' => $this->t('Jump to the first new comment.'),
-                    'data-history-node-last-comment-timestamp' => $entity->get($field_name)->last_comment_timestamp,
-                    'data-history-node-field-name' => $field_name,
-                  ),
-                );
-              }
             }
           }
-          // Provide a link to new comment form.
+
+          // Add a "add new comment" link if this entity is allowing new
+          // comments and the user has permission.
           if ($commenting_status == CommentItemInterface::OPEN) {
-            $comment_form_location = $field_definition->getSetting('form_location');
             if ($this->currentUser->hasPermission('post comments')) {
-              $links['comment-add'] = array(
-                'title' => $this->t('Add new comment'),
-                'language' => $entity->language(),
-                'attributes' => array('title' => $this->t('Share your thoughts and opinions.')),
-                'fragment' => 'comment-form',
-              );
-              if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE) {
-                $links['comment-add']['url'] = Url::fromRoute('comment.reply', [
-                  'entity_type' => $entity->getEntityTypeId(),
-                  'entity' => $entity->id(),
-                  'field_name' => $field_name,
-                ]);
+
+              // If our own view mode has visible comments, we determine the
+              // link for the comment-add form using its formatter settings.
+              // If not, we use the formatter settings for 'full' view mode,
+              // which means that the comment-add link for a teaser can link
+              // to a full node page. (This is default behavior.)
+              $display = $this->entityManager->getStorage('entity_view_display')
+                ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.' . $view_mode);
+              if (!$display) {
+                $display = $this->entityManager->getStorage('entity_view_display')
+                  ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.default');
               }
-              else {
-                $links['comment-add'] += ['url' => $entity->urlInfo()];
+              $formatter_options = $display
+                ? $display->getComponent($field_name) : NULL;
+              $fallback_to_full = !$formatter_options && $view_mode != 'full';
+              if ($fallback_to_full) {
+                $formatter_options = $formatter_options_full;
               }
-            }
-            elseif ($this->currentUser->isAnonymous()) {
-              $links['comment-forbidden'] = array(
-                'title' => $this->commentManager->forbiddenMessage($entity, $field_name),
-              );
-            }
-          }
-        }
-        else {
-          // Entity in other view modes: add a "post comment" link if the user
-          // is allowed to post comments and if this entity is allowing new
-          // comments.
-          if ($commenting_status == CommentItemInterface::OPEN) {
-            $comment_form_location = $field_definition->getSetting('form_location');
-            if ($this->currentUser->hasPermission('post comments')) {
-              // Show the "post comment" link if the form is on another page, or
-              // if there are existing comments that the link will skip past.
-              if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE || (!empty($entity->get($field_name)->comment_count) && $this->currentUser->hasPermission('access comments'))) {
+
+              // Show "add comment" link, unless the form is directly below it
+              // (that is, if there are no comments displayed in between).
+              if ($fallback_to_full
+                  || !$formatter_options
+                  || $formatter_options['settings']['form_location'] == CommentItemInterface::FORM_SEPARATE_PAGE
+                  || (!empty($entity->get($field_name)->comment_count)
+                      && $this->currentUser->hasPermission('access comments'))) {
                 $links['comment-add'] = array(
                   'title' => $this->t('Add new comment'),
+                  'language' => $entity->language(),
                   'attributes' => array('title' => $this->t('Share your thoughts and opinions.')),
                   'fragment' => 'comment-form',
                 );
-                if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE) {
+                if (!$formatter_options
+                    || $formatter_options['settings']['form_location'] == CommentItemInterface::FORM_SEPARATE_PAGE) {
+                  // Link to comment reply form on separate page.
                   $links['comment-add']['url'] = Url::fromRoute('comment.reply', [
                     'entity_type' => $entity->getEntityTypeId(),
                     'entity' => $entity->id(),
                     'field_name' => $field_name,
                   ]);
                 }
-                else {
+                elseif ($fallback_to_full) {
+                  // We need to link to the full node and are not yet on it.
                   $links['comment-add']['url'] = $entity->urlInfo();
                 }
+                else {
+                  // Link to the same page; we may or may not be displaying in
+                  // 'full' view mode.
+                  // @todo check the following code. Can we generate just a
+                  // href="#comment-form" somehow?
+                  // '<current>' won't work if you are viewing the front page,
+                  // because the URL will be expanded to the alias (e.g. 'node')
+                  // which will be a new request, because you are viewing '/'.
+                  if (\Drupal::hasRequest()) {
+                    $request = \Drupal::request();
+                  }
+                  else {
+                    // Necessary for unit tests.
+                    $request = Request::createFromGlobals();
+                  }
+                  $links['comment-add']['url'] = $request->getPathInfo() == '/'
+                    ? Url::fromRoute('<front>') : Url::fromRoute('<current>');
+                }
               }
             }
             elseif ($this->currentUser->isAnonymous()) {
@@ -188,30 +236,33 @@ public function buildCommentedEntityLinks(FieldableEntityInterface $entity, arra
               );
             }
           }
-        }
-      }
 
-      if (!empty($links)) {
-        $entity_links['comment__' . $field_name] = array(
-          '#theme' => 'links__entity__comment__' . $field_name,
-          '#links' => $links,
-          '#attributes' => array('class' => array('links', 'inline')),
-        );
-        if ($view_mode == 'teaser' && $this->moduleHandler->moduleExists('history') && $this->currentUser->isAuthenticated()) {
-          $entity_links['comment__' . $field_name]['#attached']['library'][] = 'comment/drupal.node-new-comments-link';
+          if (!empty($links)) {
+            $entity_links['comment__' . $field_name] = array(
+              '#theme' => 'links__entity__comment__' . $field_name,
+              '#links' => $links,
+              '#attributes' => array('class' => array('links', 'inline')),
+            );
+            if ($view_mode == 'teaser'
+                && $this->moduleHandler->moduleExists('history')
+                && $this->currentUser->isAuthenticated()
+                && $formatter_options_full) {
+              $entity_links['comment__' . $field_name]['#attached']['library'][] = 'comment/drupal.node-new-comments-link';
 
-          // Embed the metadata for the "X new comments" link (if any) on this
-          // entity.
-          $entity_links['comment__' . $field_name]['#post_render_cache']['history_attach_timestamp'] = array(
-            array('node_id' => $entity->id()),
-          );
-          $entity_links['comment__' . $field_name]['#post_render_cache']['comment.post_render_cache:attachNewCommentsLinkMetadata'] = array(
-            array(
-              'entity_type' => $entity->getEntityTypeId(),
-              'entity_id' => $entity->id(),
-              'field_name' => $field_name,
-            ),
-          );
+              // Embed the metadata for the "X new comments" link (if any) on
+              // this entity.
+              $entity_links['comment__' . $field_name]['#post_render_cache']['history_attach_timestamp'] = array(
+                array('node_id' => $entity->id()),
+              );
+              $entity_links['comment__' . $field_name]['#post_render_cache']['comment.post_render_cache:attachNewCommentsLinkMetadata'] = array(
+                array(
+                  'entity_type' => $entity->getEntityTypeId(),
+                  'entity_id' => $entity->id(),
+                  'field_name' => $field_name,
+                ),
+              );
+            }
+          }
         }
       }
     }
diff --git a/core/modules/comment/src/CommentManagerInterface.php b/core/modules/comment/src/CommentManagerInterface.php
index 2c9a531..cbcd9cd 100644
--- a/core/modules/comment/src/CommentManagerInterface.php
+++ b/core/modules/comment/src/CommentManagerInterface.php
@@ -17,16 +17,6 @@
 interface CommentManagerInterface {
 
   /**
-   * Comments are displayed in a flat list - expanded.
-   */
-  const COMMENT_MODE_FLAT = 0;
-
-  /**
-   * Comments are displayed as a threaded list - expanded.
-   */
-  const COMMENT_MODE_THREADED = 1;
-
-  /**
    * Utility function to return an array of comment fields.
    *
    * @param string $entity_type_id
diff --git a/core/modules/comment/src/CommentPostRenderCache.php b/core/modules/comment/src/CommentPostRenderCache.php
index 0348cc3..2f5c4ca 100644
--- a/core/modules/comment/src/CommentPostRenderCache.php
+++ b/core/modules/comment/src/CommentPostRenderCache.php
@@ -271,9 +271,23 @@ public function attachNewCommentsLinkMetadata(array $element, array $context) {
     }
 
     $field_name = $context['field_name'];
-    $page_number = $this->entityManager
-      ->getStorage('comment')
-      ->getNewCommentPageNumber($entity->{$field_name}->comment_count, $new, $entity);
+
+    // Find the current display page for this comment. We link to it using the
+    // standard node urlInfo, i.e. the full/default view mode.
+    $page_number = 0;
+    $display = \Drupal::entityManager()->getStorage('entity_view_display')
+      ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.full');
+    if (!$display) {
+      $display = \Drupal::entityManager()->getStorage('entity_view_display')
+        ->load($entity->getEntityTypeId() . '.' . $entity->bundle() . '.default');
+    }
+    $formatter_options = $display ? $display->getComponent($field_name) : NULL;
+    if ($formatter_options) {
+      $field_definition = \Drupal::entityManager()->getFieldStorageDefinitions($entity->getEntityTypeId())[$field_name];
+      $comment_type = \Drupal::entityManager()->getStorage('comment_type')->load($field_definition->getSetting('comment_type'));
+      $page_number = \Drupal::entityManager()->getStorage('comment')
+        ->getNewCommentPageNumber($entity->{$field_name}->comment_count, $new, $entity, $comment_type->getThreadingMode(), $formatter_options['settings']['per_page']);
+    }
     $query = $page_number ? array('page' => $page_number) : NULL;
 
     // Attach metadata.
diff --git a/core/modules/comment/src/CommentStorage.php b/core/modules/comment/src/CommentStorage.php
index b4977fa..89e7159 100644
--- a/core/modules/comment/src/CommentStorage.php
+++ b/core/modules/comment/src/CommentStorage.php
@@ -111,7 +111,7 @@ public function getDisplayOrdinal(CommentInterface $comment, $comment_mode, $div
       $query->condition('c1.status', CommentInterface::PUBLISHED);
     }
 
-    if ($comment_mode == CommentManagerInterface::COMMENT_MODE_FLAT) {
+    if ($comment_mode == CommentTypeInterface::THREADING_MODE_FLAT) {
       // For rendering flat comments, cid is used for ordering comments due to
       // unpredictable behavior with timestamp, so we make the same assumption
       // here.
@@ -135,15 +135,13 @@ public function getDisplayOrdinal(CommentInterface $comment, $comment_mode, $div
   /**
    * {@inheritdoc}
    */
-  public function getNewCommentPageNumber($total_comments, $new_comments, FieldableEntityInterface $entity, $field_name = 'comment') {
-    $field = $entity->getFieldDefinition($field_name);
-    $comments_per_page = $field->getSetting('per_page');
+  public function getNewCommentPageNumber($total_comments, $new_comments, FieldableEntityInterface $entity, $mode = CommentTypeInterface::THREADING_MODE_THREADED, $comments_per_page = 50, $field_name = 'comment') {
 
     if ($total_comments <= $comments_per_page) {
       // Only one page of comments.
       $count = 0;
     }
-    elseif ($field->getSetting('default_mode') == CommentManagerInterface::COMMENT_MODE_FLAT) {
+    elseif ($mode == CommentTypeInterface::THREADING_MODE_FLAT) {
       // Flat comments.
       $count = $total_comments - $new_comments;
     }
@@ -304,7 +302,7 @@ public function loadThread(EntityInterface $entity, $field_name, $mode, $comment
         $count_query->condition('c.status', CommentInterface::PUBLISHED);
       }
     }
-    if ($mode == CommentManagerInterface::COMMENT_MODE_FLAT) {
+    if ($mode == CommentTypeInterface::THREADING_MODE_FLAT) {
       $query->orderBy('c.cid', 'ASC');
     }
     else {
diff --git a/core/modules/comment/src/CommentStorageInterface.php b/core/modules/comment/src/CommentStorageInterface.php
index 5be4776..aa0dfe0 100644
--- a/core/modules/comment/src/CommentStorageInterface.php
+++ b/core/modules/comment/src/CommentStorageInterface.php
@@ -48,13 +48,18 @@ public function getMaxThreadPerThread(CommentInterface $comment);
    *   The number of new comments that the entity has.
    * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
    *   The entity to which the comments belong.
+   * @param int $mode
+   *   (optional) The threading mode: CommentTypeInterface::THREADING_MODE_FLAT
+   *   or CommentTypeInterface::THREADING_MODE_THREADED (the default).
+   * @param int $comments_per_page
+   *   (optional) The amount of comments to display per page. Defaults to 50.
    * @param string $field_name
    *   The field name on the entity to which comments are attached.
    *
    * @return array|null
    *   The page number where first new comment appears. (First page returns 0.)
    */
-  public function getNewCommentPageNumber($total_comments, $new_comments, FieldableEntityInterface $entity, $field_name = 'comment');
+  public function getNewCommentPageNumber($total_comments, $new_comments, FieldableEntityInterface $entity, $mode = CommentTypeInterface::THREADING_MODE_THREADED, $comments_per_page = 50, $field_name = 'comment');
 
   /**
    * Gets the display ordinal or page number for a comment.
@@ -62,8 +67,8 @@ public function getNewCommentPageNumber($total_comments, $new_comments, Fieldabl
    * @param \Drupal\comment\CommentInterface $comment
    *   The comment to use as a reference point.
    * @param int $comment_mode
-   *   The comment display mode: CommentManagerInterface::COMMENT_MODE_FLAT or
-   *   CommentManagerInterface::COMMENT_MODE_THREADED.
+   *   The threading mode: CommentTypeInterface::THREADING_MODE_FLAT or
+   *   CommentTypeInterface::THREADING_MODE_THREADED.
    * @param int $divisor
    *   Defaults to 1, which returns the display ordinal for a comment. If the
    *   number of comments per page is provided, the returned value will be the
@@ -93,8 +98,8 @@ public function getChildCids(array $comments);
    * @param string $field_name
    *   The field_name whose comment(s) needs rendering.
    * @param int $mode
-   *   The comment display mode: CommentManagerInterface::COMMENT_MODE_FLAT or
-   *   CommentManagerInterface::COMMENT_MODE_THREADED.
+   *   The threading mode: CommentTypeInterface::THREADING_MODE_FLAT or
+   *   CommentTypeInterface::THREADING_MODE_THREADED.
    * @param int $comments_per_page
    *   (optional) The amount of comments to display per page.
    *   Defaults to 0, which means show all comments.
diff --git a/core/modules/comment/src/CommentTypeForm.php b/core/modules/comment/src/CommentTypeForm.php
index 3c7ef6a..12659b3 100644
--- a/core/modules/comment/src/CommentTypeForm.php
+++ b/core/modules/comment/src/CommentTypeForm.php
@@ -75,6 +75,7 @@ public function __construct(EntityManagerInterface $entity_manager, LoggerInterf
   public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
+    /** @var $comment_type CommentTypeInterface */
     $comment_type = $this->entity;
 
     $form['label'] = array(
@@ -126,6 +127,13 @@ public function form(array $form, FormStateInterface $form_state) {
       );
     }
 
+    $form['threading_mode'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Threading'),
+      '#default_value' => $comment_type->getThreadingMode(),
+      '#description' => t('Show comment replies in a threaded list.'),
+    );
+
     if ($this->moduleHandler->moduleExists('content_translation')) {
       $form['language'] = array(
         '#type' => 'details',
diff --git a/core/modules/comment/src/CommentTypeInterface.php b/core/modules/comment/src/CommentTypeInterface.php
index 2ccc0c1..b7015a7 100644
--- a/core/modules/comment/src/CommentTypeInterface.php
+++ b/core/modules/comment/src/CommentTypeInterface.php
@@ -15,6 +15,16 @@
 interface CommentTypeInterface extends ConfigEntityInterface {
 
   /**
+   * Comments are displayed as a flat list.
+   */
+  const THREADING_MODE_FLAT = 0;
+
+  /**
+   * Comments are displayed as a threaded list.
+   */
+  const THREADING_MODE_THREADED = 1;
+
+  /**
    * Returns the comment type description.
    *
    * @return string
@@ -40,4 +50,23 @@ public function setDescription($description);
    */
   public function getTargetEntityTypeId();
 
+  /**
+   * Gets the threading mode for this comment type.
+   *
+   * @return int
+   *   The comment threading mode (CommentTypeInterface::THREADING_MODE_FLAT or
+   *   CommentTypeInterface::THREADING_MODE_THREADED)
+   */
+  public function getThreadingMode();
+
+  /**
+   * Sets the threading mode for this comment type.
+   *
+   * @param int $mode
+   *   The threading mode.
+   *
+   * @return $this
+   */
+  public function setThreadingMode($mode);
+
 }
diff --git a/core/modules/comment/src/CommentViewBuilder.php b/core/modules/comment/src/CommentViewBuilder.php
index bf0f526..72e5d90 100644
--- a/core/modules/comment/src/CommentViewBuilder.php
+++ b/core/modules/comment/src/CommentViewBuilder.php
@@ -8,7 +8,6 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityViewBuilder;
 
@@ -23,9 +22,13 @@ class CommentViewBuilder extends EntityViewBuilder {
   protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) {
     $build = parent::getBuildDefaults($entity, $view_mode, $langcode);
 
+    // Threading mode setting is stored in comment_type config; the name of the
+    // specific comment type is stored in our field definition.
+    $field_definition = $this->entityManager->getFieldStorageDefinitions($entity->getCommentedEntity()->getEntityTypeId())[$entity->getFieldName()];
+    $comment_type = $this->entityManager->getStorage('comment_type')->load($field_definition->getSetting('comment_type'));
     // If threading is enabled, don't render cache individual comments, but do
     // keep the cache tags, so they can bubble up.
-    if ($entity->getCommentedEntity()->getFieldDefinition($entity->getFieldName())->getSetting('default_mode') === CommentManagerInterface::COMMENT_MODE_THREADED) {
+    if ($comment_type->getThreadingMode() === CommentTypeInterface::THREADING_MODE_THREADED) {
       $cache_tags = $build['#cache']['tags'];
       $build['#cache'] = [];
       $build['#cache']['tags'] = $cache_tags;
@@ -137,9 +140,10 @@ protected function alterBuild(array &$build, EntityInterface $comment, EntityVie
     if (empty($comment->in_preview)) {
       $prefix = '';
       $commented_entity = $comment->getCommentedEntity();
-      $field_definition = $this->entityManager->getFieldDefinitions($commented_entity->getEntityTypeId(), $commented_entity->bundle())[$comment->getFieldName()];
+      $field_definition = $this->entityManager->getFieldStorageDefinitions($commented_entity->getEntityTypeId())[$comment->getFieldName()];
+      $comment_type = $this->entityManager->getStorage('comment_type')->load($field_definition->getSetting('comment_type'));
       $is_threaded = isset($comment->divs)
-        && $field_definition->getSetting('default_mode') == CommentManagerInterface::COMMENT_MODE_THREADED;
+        && $comment_type->getThreadingMode() == CommentTypeInterface::THREADING_MODE_THREADED;
 
       // Add indentation div or close open divs as needed.
       if ($is_threaded) {
diff --git a/core/modules/comment/src/Controller/CommentController.php b/core/modules/comment/src/Controller/CommentController.php
index 05baad8..e17820d 100644
--- a/core/modules/comment/src/Controller/CommentController.php
+++ b/core/modules/comment/src/Controller/CommentController.php
@@ -9,6 +9,7 @@
 
 use Drupal\comment\CommentInterface;
 use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Entity\EntityInterface;
@@ -123,10 +124,12 @@ public function commentPermalink(Request $request, CommentInterface $comment) {
       if (!$entity->access('view')) {
         throw new AccessDeniedHttpException();
       }
-      $field_definition = $this->entityManager()->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle())[$comment->getFieldName()];
-
+      $field_definition = $this->entityManager()->getFieldStorageDefinitions($entity->getEntityTypeId())[$comment->getFieldName()];
+      $comment_type = $this->entityManager()->getStorage('comment_type')->load($field_definition->getSetting('comment_type'));
+      $display_settings = entity_get_display($entity->getEntityTypeId(), $entity->bundle(), 'default')
+        ->getComponent($comment->getFieldName());
       // Find the current display page for this comment.
-      $page = $this->entityManager()->getStorage('comment')->getDisplayOrdinal($comment, $field_definition->getSetting('default_mode'), $field_definition->getSetting('per_page'));
+      $page = $this->entityManager()->getStorage('comment')->getDisplayOrdinal($comment, $comment_type->getThreadingMode(), $display_settings['settings']['per_page']);
       // @todo: Cleaner sub request handling.
       $redirect_request = Request::create($entity->url(), 'GET', $request->query->all(), $request->cookies->all(), array(), $request->server->all());
       $redirect_request->query->set('page', $page);
@@ -313,11 +316,27 @@ public function renderNewCommentsNodeLinks(Request $request) {
     $nids = array_slice($nids, 0, 100);
 
     $links = array();
-    foreach ($nids as $nid) {
-      $node = $this->entityManager->getStorage('node')->load($nid);
+    $nodes = $this->entityManager->getStorage('node')->loadMultiple($nids);
+    foreach ($nodes as $nid => $node) {
       $new = $this->commentManager->getCountNewComments($node);
-      $page_number = $this->entityManager()->getStorage('comment')
-        ->getNewCommentPageNumber($node->{$field_name}->comment_count, $new, $node);
+
+      // Find the current display page for this comment. We link to it using the
+      // standard node urlInfo, i.e. the full/default view mode.
+      $page_number = 0;
+      $display = $this->entityManager->getStorage('entity_view_display')
+        ->load('node.' . $node->bundle() . '.full');
+      if (!$display) {
+        $display = $this->entityManager->getStorage('entity_view_display')
+          ->load('node.' . $node->bundle() . '.default');
+      }
+      $formatter_options = $display ? $display->getComponent($field_name) : NULL;
+      if ($formatter_options) {
+        $field_definition = $this->entityManager->getFieldStorageDefinitions('node')[$field_name];
+        $comment_type = $this->entityManager->getStorage('comment_type')->load($field_definition->getSetting('comment_type'));
+        $page_number = $this->entityManager->getStorage('comment')
+          ->getNewCommentPageNumber($node->{$field_name}->comment_count, $new, $node, $comment_type->getThreadingMode(), $formatter_options['settings']['per_page']);
+      }
+
       $query = $page_number ? array('page' => $page_number) : NULL;
       $links[$nid] = array(
         'new_comment_count' => (int) $new,
diff --git a/core/modules/comment/src/Entity/CommentType.php b/core/modules/comment/src/Entity/CommentType.php
index fb41442..7d14295 100644
--- a/core/modules/comment/src/Entity/CommentType.php
+++ b/core/modules/comment/src/Entity/CommentType.php
@@ -72,6 +72,13 @@ class CommentType extends ConfigEntityBundleBase implements CommentTypeInterface
   protected $target_entity_type_id;
 
   /**
+   * The comment threading mode (flat or threaded).
+   *
+   * @var int
+   */
+  protected $threading_mode;
+
+  /**
    * {@inheritdoc}
    */
   public function getDescription() {
@@ -93,4 +100,19 @@ public function getTargetEntityTypeId() {
     return $this->target_entity_type_id;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getThreadingMode() {
+    return isset($this->threading_mode) ? $this->threading_mode :
+      CommentTypeInterface::THREADING_MODE_THREADED;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setThreadingMode($mode) {
+    $this->threading_mode = $mode;
+    return $this;
+  }
 }
diff --git a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
index 75b85f0..526f6b2 100644
--- a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
+++ b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
@@ -7,19 +7,15 @@
 
 namespace Drupal\comment\Plugin\Field\FieldFormatter;
 
-use Drupal\comment\CommentManagerInterface;
-use Drupal\comment\CommentStorageInterface;
-use Drupal\comment\Entity\Comment;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\EntityViewBuilderInterface;
 use Drupal\Core\Entity\EntityFormBuilderInterface;
 use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FormatterBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -45,6 +41,8 @@ class CommentDefaultFormatter extends FormatterBase implements ContainerFactoryP
   public static function defaultSettings() {
     return array(
       'pager_id' => 0,
+      'per_page' => 50,
+      'form_location' => CommentItemInterface::FORM_BELOW,
     ) + parent::defaultSettings();
   }
 
@@ -97,7 +95,9 @@ public static function create(ContainerInterface $container, array $configuratio
       $configuration['third_party_settings'],
       $container->get('current_user'),
       $container->get('entity.manager'),
-      $container->get('entity.form_builder')
+      $container->get('entity.form_builder'),
+      $container->get('module_handler'),
+      $container->get('comment.manager')
     );
   }
 
@@ -151,7 +151,8 @@ public function viewElements(FieldItemListInterface $items) {
       // comment_node_update_index() instead of by this formatter, so don't
       // return anything if the view mode is search_index or search_result.
       !in_array($this->viewMode, array('search_result', 'search_index'))) {
-      $comment_settings = $this->getFieldSettings();
+
+      $comment_type = $this->entityManager->getStorage('comment_type')->load($this->getFieldSetting('comment_type'));
 
       // Only attempt to render comments if the entity has visible comments.
       // Unpublished comments are not included in
@@ -164,8 +165,8 @@ public function viewElements(FieldItemListInterface $items) {
         $output['comments']['#cache']['tags'] = $this->entityManager->getDefinition('comment')->getListCacheTags();
 
         if ($entity->get($field_name)->comment_count || $this->currentUser->hasPermission('administer comments')) {
-          $mode = $comment_settings['default_mode'];
-          $comments_per_page = $comment_settings['per_page'];
+          $mode = $comment_type->getThreadingMode();
+          $comments_per_page = $this->getSetting('per_page');
           $comments = $this->storage->loadThread($entity, $field_name, $mode, $comments_per_page, $this->getSetting('pager_id'));
           if ($comments) {
             comment_prepare_thread($comments);
@@ -181,7 +182,7 @@ public function viewElements(FieldItemListInterface $items) {
 
       // Append comment form if the comments are open and the form is set to
       // display below the entity. Do not show the form for the print view mode.
-      if ($status == CommentItemInterface::OPEN && $comment_settings['form_location'] == CommentItemInterface::FORM_BELOW && $this->viewMode != 'print') {
+      if ($status == CommentItemInterface::OPEN && $this->getSetting('form_location') == CommentItemInterface::FORM_BELOW && $this->viewMode != 'print') {
         // Only show the add comment form if the user has permission.
         $elements['#cache']['contexts'][] = 'user.roles';
         if ($this->currentUser->hasPermission('post comments')) {
@@ -221,7 +222,7 @@ public function viewElements(FieldItemListInterface $items) {
 
       $elements[] = $output + array(
         '#comment_type' => $this->getFieldSetting('comment_type'),
-        '#comment_display_mode' => $this->getFieldSetting('default_mode'),
+        '#comment_threading_mode' => $comment_type->getThreadingMode(),
         'comments' => array(),
         'comment_form' => array(),
       );
@@ -235,6 +236,20 @@ public function viewElements(FieldItemListInterface $items) {
    */
   public function settingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
+    $element['per_page'] = array(
+      '#type' => 'number',
+      '#title' => t('Comments per page'),
+      '#default_value' => $this->getSetting('per_page'),
+      '#required' => TRUE,
+      '#min' => 10,
+      '#max' => 1000,
+      '#step' => 10,
+    );
+    $element['form_location'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show reply form on the same page as comments'),
+      '#default_value' => $this->getSetting('form_location'),
+    );
     $element['pager_id'] = array(
       '#type' => 'select',
       '#title' => $this->t('Pager ID'),
@@ -249,13 +264,17 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    // Only show a summary if we're using a non-standard pager id.
+    $variables = array(
+      '@id' => $this->getSetting('pager_id'),
+      '@form' => $this->getSetting('form_location') ? $this->t('inline form') : $this->t('form on separate page'),
+      '@per_page' => $this->getSetting('per_page'),
+    );
     if ($this->getSetting('pager_id')) {
-      return array($this->t('Pager ID: @id', array(
-        '@id' => $this->getSetting('pager_id'),
-      )));
+      // Only include pager details in summary if we're using a non-standard
+      // pager id.
+      return array($this->t('Showing @per_page comments with @form, using pager ID @id', $variables));
     }
-    return array();
+    return array($this->t('Showing @per_page comments with @form', $variables));
   }
 
 }
diff --git a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
index c53fd64..2e485dc 100644
--- a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
+++ b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
@@ -46,9 +46,6 @@ public static function defaultStorageSettings() {
    */
   public static function defaultFieldSettings() {
     return array(
-      'default_mode' => CommentManagerInterface::COMMENT_MODE_THREADED,
-      'per_page' => 50,
-      'form_location' => CommentItemInterface::FORM_BELOW,
       'anonymous' => COMMENT_ANONYMOUS_MAYNOT_CONTACT,
       'preview' => DRUPAL_OPTIONAL,
     ) + parent::defaultFieldSettings();
@@ -110,21 +107,6 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
 
     $anonymous_user = new AnonymousUserSession();
 
-    $element['default_mode'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Threading'),
-      '#default_value' => $settings['default_mode'],
-      '#description' => t('Show comment replies in a threaded list.'),
-    );
-    $element['per_page'] = array(
-      '#type' => 'number',
-      '#title' => t('Comments per page'),
-      '#default_value' => $settings['per_page'],
-      '#required' => TRUE,
-      '#min' => 10,
-      '#max' => 1000,
-      '#step' => 10,
-    );
     $element['anonymous'] = array(
       '#type' => 'select',
       '#title' => t('Anonymous commenting'),
@@ -136,11 +118,6 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
       ),
       '#access' => $anonymous_user->hasPermission('post comments'),
     );
-    $element['form_location'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show reply form on the same page as comments'),
-      '#default_value' => $settings['form_location'],
-    );
     $element['preview'] = array(
       '#type' => 'radios',
       '#title' => t('Preview comment'),
diff --git a/core/modules/comment/src/Plugin/views/field/NodeNewComments.php b/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
index 695bd91..d2eaa61 100644
--- a/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
+++ b/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
@@ -96,6 +96,21 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       '#type' => 'checkbox',
       '#default_value' => $this->options['link_to_comment'],
     );
+    $form['threading_mode'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Threading'),
+      '#default_value' => $this->options['threading_mode'],
+      '#description' => t('Comment replies use a threaded list.'),
+    );
+    $element['per_page'] = array(
+      '#type' => 'number',
+      '#title' => t('Comments per page'),
+      '#default_value' => $this->options['per_page'],
+      '#required' => TRUE,
+      '#min' => 10,
+      '#max' => 1000,
+      '#step' => 10,
+    );
 
     parent::buildOptionsForm($form, $form_state);
   }
@@ -166,7 +181,7 @@ protected function renderLink($data, ResultRow $values) {
         'type' => $this->getValue($values, 'type'),
       ));
       $page_number = \Drupal::entityManager()->getStorage('comment')
-        ->getNewCommentPageNumber($this->getValue($values, 'comment_count'), $this->getValue($values), $node);
+        ->getNewCommentPageNumber($this->getValue($values, 'comment_count'), $this->getValue($values), $node, $this->options['threading_mode'], $this->options['per_page']);
       $this->options['alter']['make_link'] = TRUE;
       $this->options['alter']['url'] = $node->urlInfo();
       $this->options['alter']['query'] = $page_number ? array('page' => $page_number) : NULL;
diff --git a/core/modules/comment/src/Tests/CommentCacheTagsTest.php b/core/modules/comment/src/Tests/CommentCacheTagsTest.php
index fa95260..3f248d1 100644
--- a/core/modules/comment/src/Tests/CommentCacheTagsTest.php
+++ b/core/modules/comment/src/Tests/CommentCacheTagsTest.php
@@ -7,9 +7,9 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
+use Drupal\comment\Entity\CommentType;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\field\Entity\FieldConfig;
 use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
 use Drupal\user\Entity\Role;
 use Drupal\user\RoleInterface;
@@ -53,9 +53,9 @@ protected function createEntity() {
     $this->addDefaultCommentField('entity_test', 'bar', 'comment');
 
     // Display comments in a flat list; threaded comments are not render cached.
-    $field = FieldConfig::loadByName('entity_test', 'bar', 'comment');
-    $field->settings['default_mode'] = CommentManagerInterface::COMMENT_MODE_FLAT;
-    $field->save();
+    $comment_type = CommentType::load('comment');
+    $comment_type->setThreadingMode(CommentTypeInterface::THREADING_MODE_FLAT);
+    $comment_type->save();
 
     // Create a "Camelids" test entity.
     $entity_test = entity_create('entity_test', array(
diff --git a/core/modules/comment/src/Tests/CommentInterfaceTest.php b/core/modules/comment/src/Tests/CommentInterfaceTest.php
index c775553..c178416 100644
--- a/core/modules/comment/src/Tests/CommentInterfaceTest.php
+++ b/core/modules/comment/src/Tests/CommentInterfaceTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\comment\Entity\Comment;
 use Drupal\user\RoleInterface;
@@ -29,7 +29,7 @@ public function setUp() {
     $this->setCommentPreview(DRUPAL_DISABLED);
     $this->setCommentForm(TRUE);
     $this->setCommentSubject(FALSE);
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED);
     $this->drupalLogout();
   }
 
diff --git a/core/modules/comment/src/Tests/CommentLinksTest.php b/core/modules/comment/src/Tests/CommentLinksTest.php
index 8dc3b5b..be74d6b 100644
--- a/core/modules/comment/src/Tests/CommentLinksTest.php
+++ b/core/modules/comment/src/Tests/CommentLinksTest.php
@@ -7,9 +7,9 @@
 
 namespace Drupal\comment\Tests;
 
+use Drupal\comment\CommentInterface;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Language\LanguageInterface;
-use Drupal\comment\CommentInterface;
 use Drupal\user\RoleInterface;
 
 /**
@@ -76,7 +76,7 @@ public function testCommentLinks() {
     $this->comment = $comment;
 
     // Change comment settings.
-    $this->setCommentSettings('form_location', CommentItemInterface::FORM_BELOW, 'Set comment form location');
+    $this->setCommentFormatterSettings('form_location', CommentItemInterface::FORM_BELOW, 'Set comment form location');
     $this->setCommentAnonymous(TRUE);
     $this->node->comment = CommentItemInterface::OPEN;
     $this->node->save();
diff --git a/core/modules/comment/src/Tests/CommentNodeAccessTest.php b/core/modules/comment/src/Tests/CommentNodeAccessTest.php
index 175feba..1ffc73b 100644
--- a/core/modules/comment/src/Tests/CommentNodeAccessTest.php
+++ b/core/modules/comment/src/Tests/CommentNodeAccessTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 
 /**
  * Tests comments with node access.
@@ -54,7 +54,7 @@ function testThreadedCommentView() {
     $this->setCommentPreview(DRUPAL_DISABLED);
     $this->setCommentForm(TRUE);
     $this->setCommentSubject(TRUE);
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED);
     $this->drupalLogout();
 
     // Post comment.
diff --git a/core/modules/comment/src/Tests/CommentPagerTest.php b/core/modules/comment/src/Tests/CommentPagerTest.php
index ca1c5a6..15b001c 100644
--- a/core/modules/comment/src/Tests/CommentPagerTest.php
+++ b/core/modules/comment/src/Tests/CommentPagerTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 use Drupal\Component\Utility\String;
 use Drupal\node\Entity\Node;
 
@@ -35,7 +35,7 @@ function testCommentPaging() {
     $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE);
     $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE);
 
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_FLAT);
 
     // Set comments to one per page so that we are able to test paging without
     // needing to insert large numbers of comments.
@@ -75,7 +75,7 @@ function testCommentPaging() {
     // If we switch to threaded mode, the replies on the oldest comment
     // should be bumped to the first page and comment 6 should be bumped
     // to the second page.
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Switched to threaded mode.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED, 'Switched to threaded mode.');
     $this->drupalGet('node/' . $node->id(), array('query' => array('page' => 0)));
     $this->assertTrue($this->commentExists($reply, TRUE), 'In threaded mode, reply appears on page 1.');
     $this->assertFalse($this->commentExists($comments[1]), 'In threaded mode, comment 2 has been bumped off of page 1.');
@@ -141,7 +141,7 @@ function testCommentOrderingThreading() {
     // - 2
     //   - 5
 
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_FLAT);
 
     $expected_order = array(
       0,
@@ -155,7 +155,7 @@ function testCommentOrderingThreading() {
     $this->drupalGet('node/' . $node->id());
     $this->assertCommentOrder($comments, $expected_order);
 
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Switched to threaded mode.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED, 'Switched to threaded mode.');
 
     $expected_order = array(
       0,
@@ -236,7 +236,7 @@ function testCommentNewPageIndicator() {
     // - 2
     //   - 5
 
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_FLAT);
 
     $expected_pages = array(
       1 => 5, // Page of comment 5
@@ -250,11 +250,11 @@ function testCommentNewPageIndicator() {
     $node = Node::load($node->id());
     foreach ($expected_pages as $new_replies => $expected_page) {
       $returned_page = \Drupal::entityManager()->getStorage('comment')
-        ->getNewCommentPageNumber($node->get('comment')->comment_count, $new_replies, $node);
+        ->getNewCommentPageNumber($node->get('comment')->comment_count, $new_replies, $node, CommentTypeInterface::THREADING_MODE_FLAT, 1);
       $this->assertIdentical($expected_page, $returned_page, format_string('Flat mode, @new replies: expected page @expected, returned page @returned.', array('@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page)));
     }
 
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Switched to threaded mode.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED, 'Switched to threaded mode.');
 
     $expected_pages = array(
       1 => 5, // Page of comment 5
@@ -269,7 +269,7 @@ function testCommentNewPageIndicator() {
     $node = Node::load($node->id());
     foreach ($expected_pages as $new_replies => $expected_page) {
       $returned_page = \Drupal::entityManager()->getStorage('comment')
-        ->getNewCommentPageNumber($node->get('comment')->comment_count, $new_replies, $node);
+        ->getNewCommentPageNumber($node->get('comment')->comment_count, $new_replies, $node, CommentTypeInterface::THREADING_MODE_THREADED, 1);
       $this->assertEqual($expected_page, $returned_page, format_string('Threaded mode, @new replies: expected page @expected, returned page @returned.', array('@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page)));
     }
   }
@@ -296,16 +296,16 @@ function testTwoPagers() {
     $account = $this->drupalCreateUser(array('administer node display'));
     $this->drupalLogin($account);
     $this->drupalGet('admin/structure/types/manage/article/display');
-    $this->assertNoText(t('Pager ID: @id', array('@id' => 0)), 'No summary for standard pager');
-    $this->assertText(t('Pager ID: @id', array('@id' => 1)));
+    $this->assertNoText(t(' using pager ID @id', array('@id' => 0)), 'No summary for standard pager');
+    $this->assertText(t(' using pager ID @id', array('@id' => 1)));
     $this->drupalPostAjaxForm(NULL, array(), 'comment_settings_edit');
     // Change default pager to 2.
     $this->drupalPostForm(NULL, array('fields[comment][settings_edit_form][settings][pager_id]' => 2), t('Save'));
-    $this->assertText(t('Pager ID: @id', array('@id' => 2)));
+    $this->assertText(t(' using pager ID @id', array('@id' => 2)));
     // Revert the changes back.
     $this->drupalPostAjaxForm(NULL, array(), 'comment_settings_edit');
     $this->drupalPostForm(NULL, array('fields[comment][settings_edit_form][settings][pager_id]' => 0), t('Save'));
-    $this->assertNoText(t('Pager ID: @id', array('@id' => 0)), 'No summary for standard pager');
+    $this->assertNoText(t(' using pager ID @id', array('@id' => 0)), 'No summary for standard pager');
 
     $this->drupalLogin($this->adminUser);
 
@@ -316,7 +316,7 @@ function testTwoPagers() {
     foreach (array('comment', 'comment_2') as $field_name) {
       $this->setCommentForm(TRUE, $field_name);
       $this->setCommentPreview(DRUPAL_OPTIONAL, $field_name);
-      $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.', $field_name);
+      $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_FLAT);
 
       // Set comments to one per page so that we are able to test paging without
       // needing to insert large numbers of comments.
diff --git a/core/modules/comment/src/Tests/CommentPreviewTest.php b/core/modules/comment/src/Tests/CommentPreviewTest.php
index ae65f88..8f5f717 100644
--- a/core/modules/comment/src/Tests/CommentPreviewTest.php
+++ b/core/modules/comment/src/Tests/CommentPreviewTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\comment\Entity\Comment;
 
@@ -36,7 +36,7 @@ function testCommentPreview() {
     $this->setCommentPreview(DRUPAL_OPTIONAL);
     $this->setCommentForm(TRUE);
     $this->setCommentSubject(TRUE);
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED);
     $this->drupalLogout();
 
     // Login as web user and add a signature and a user picture.
@@ -79,7 +79,7 @@ function testCommentEditPreviewSave() {
     $this->setCommentPreview(DRUPAL_OPTIONAL);
     $this->setCommentForm(TRUE);
     $this->setCommentSubject(TRUE);
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED);
 
     $edit = array();
     $date = new DrupalDateTime('2008-03-02 17:23');
diff --git a/core/modules/comment/src/Tests/CommentStatisticsTest.php b/core/modules/comment/src/Tests/CommentStatisticsTest.php
index 99c2955..2f62b0a 100644
--- a/core/modules/comment/src/Tests/CommentStatisticsTest.php
+++ b/core/modules/comment/src/Tests/CommentStatisticsTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 use Drupal\comment\Entity\Comment;
 use Drupal\user\RoleInterface;
 
@@ -50,7 +50,7 @@ function testCommentNodeCommentStatistics() {
     $this->setCommentPreview(DRUPAL_DISABLED);
     $this->setCommentForm(TRUE);
     $this->setCommentSubject(FALSE);
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED);
     $this->drupalLogout();
 
     // Checks the initial values of node comment statistics with no comment.
diff --git a/core/modules/comment/src/Tests/CommentTestBase.php b/core/modules/comment/src/Tests/CommentTestBase.php
index 12d17c6..b388a52 100644
--- a/core/modules/comment/src/Tests/CommentTestBase.php
+++ b/core/modules/comment/src/Tests/CommentTestBase.php
@@ -84,6 +84,20 @@ protected function setUp() {
     // Create comment field on article.
     $this->addDefaultCommentField('node', 'article');
 
+    // Set some display options for search results and print pages.
+    if ($this->container->get('module_handler')->moduleExists('book')) {
+      $display = entity_get_display('node', 'article', 'print');
+      $display->removeComponent('comment');
+      $display->save();
+    }
+    if ($this->container->get('module_handler')->moduleExists('search')) {
+      foreach (array('search_result', 'search_index') as $view_mode) {
+        $display = entity_get_display('node', 'article', $view_mode);
+        $display->removeComponent('comment');
+        $display->save();
+      }
+    }
+
     // Create a test node authored by the web user.
     $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'uid' => $this->webUser->id()));
   }
@@ -270,7 +284,7 @@ public function setCommentPreview($mode, $field_name = 'comment') {
    *   Defaults to 'comment'.
    */
   public function setCommentForm($enabled, $field_name = 'comment') {
-    $this->setCommentSettings('form_location', ($enabled ? CommentItemInterface::FORM_BELOW : CommentItemInterface::FORM_SEPARATE_PAGE), 'Comment controls ' . ($enabled ? 'enabled' : 'disabled') . '.', $field_name);
+    $this->setCommentFormatterSettings('form_location', ($enabled ? CommentItemInterface::FORM_BELOW : CommentItemInterface::FORM_SEPARATE_PAGE), 'Comment controls ' . ($enabled ? 'enabled' : 'disabled') . '.', $field_name);
   }
 
   /**
@@ -296,11 +310,27 @@ function setCommentAnonymous($level) {
    *   Defaults to 'comment'.
    */
   public function setCommentsPerPage($number, $field_name = 'comment') {
-    $this->setCommentSettings('per_page', $number, format_string('Number of comments per page set to @number.', array('@number' => $number)), $field_name);
+    $this->setCommentFormatterSettings('per_page', $number, format_string('Number of comments per page set to @number.', array('@number' => $number)), $field_name);
+  }
+
+  /**
+   * Sets the threading mode for this comment type.
+   *
+   * @param int $mode
+   *   The threading mode.
+   * @param string $message
+   *   (optional) Status message to display. Defaults to 'Comment threading
+   *   changed.'
+   */
+  public function setThreadingMode($mode, $message = 'Comment threading changed.') {
+    $comment_type = CommentType::load('comment');
+    $comment_type->setThreadingMode($mode);
+    $comment_type->save();
+    $this->pass($message);
   }
 
   /**
-   * Sets a comment settings variable for the article content type.
+   * Sets a comment field settings variable for the article content type.
    *
    * @param string $name
    *   Name of variable.
@@ -321,6 +351,32 @@ public function setCommentSettings($name, $value, $message, $field_name = 'comme
   }
 
   /**
+   * Sets a display formatter settings variable for the article content type.
+   *
+   * @param string $name
+   *   Name of variable.
+   * @param string $value
+   *   Value of variable.
+   * @param string $message
+   *   Status message to display.
+   * @param string $field_name
+   *   (optional) Field name through which the comment should be posted.
+   *   Defaults to 'comment'.
+   */
+  public function setCommentFormatterSettings($name, $value, $message, $field_name = 'comment') {
+    // Some of our tests (like CommentLinksTest) assume we are working with the
+    // 'default' display for full node pages. This works (just like default site
+    // settings do), as long as we never create/save 'full' display.
+    $display = entity_get_display('node', 'article', 'default');
+    $component = $display->getComponent($field_name);
+    $component['settings'][$name] = $value;
+    $display->setComponent($field_name, $component);
+    $display->save();
+    // Display status message.
+    $this->pass($message);
+  }
+
+  /**
    * Checks whether the commenter's contact information is displayed.
    *
    * @return boolean
diff --git a/core/modules/comment/src/Tests/CommentThreadingTest.php b/core/modules/comment/src/Tests/CommentThreadingTest.php
index ab0d9b9..eac62cf 100644
--- a/core/modules/comment/src/Tests/CommentThreadingTest.php
+++ b/core/modules/comment/src/Tests/CommentThreadingTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 
 /**
  * Tests to make sure the comment number increments properly.
@@ -24,7 +24,7 @@ function testCommentThreading() {
     $this->setCommentPreview(DRUPAL_DISABLED);
     $this->setCommentForm(TRUE);
     $this->setCommentSubject(TRUE);
-    $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED);
     $this->drupalLogout();
 
     // Create a node.
diff --git a/core/modules/comment/templates/field--comment.html.twig b/core/modules/comment/templates/field--comment.html.twig
index 879f4d5..62cb2a7 100644
--- a/core/modules/comment/templates/field--comment.html.twig
+++ b/core/modules/comment/templates/field--comment.html.twig
@@ -15,7 +15,7 @@
  * - comments: List of comments rendered through comment.html.twig.
  * - content_attributes: HTML attributes for the form title.
  * - comment_form: The 'Add new comment' form.
- * - comment_display_mode: Is the comments are threaded.
+ * - comment_threading_mode: Is non-zero if the comments are threaded.
  * - comment_type: The comment type bundle ID for the comment field.
  * - entity_type: The entity type to which the field belongs.
  * - field_name: The name of the field.
diff --git a/core/modules/comment/tests/src/Unit/CommentLinkBuilderTest.php b/core/modules/comment/tests/src/Unit/CommentLinkBuilderTest.php
index 202f6a4..fbb8e7d 100644
--- a/core/modules/comment/tests/src/Unit/CommentLinkBuilderTest.php
+++ b/core/modules/comment/tests/src/Unit/CommentLinkBuilderTest.php
@@ -8,11 +8,12 @@
 namespace Drupal\Tests\comment\Unit;
 
 use Drupal\comment\CommentLinkBuilder;
+use Drupal\comment\CommentTypeInterface;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Url;
-use Drupal\node\NodeInterface;
 use Drupal\simpletest\TestBase;
 use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * @coversDefaultClass \Drupal\comment\CommentLinkBuilder
@@ -21,6 +22,55 @@
 class CommentLinkBuilderTest extends UnitTestCase {
 
   /**
+   * Entity manager mock.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityManager;
+
+  /**
+   * Entity storage mock which knows entity_view_display load method/argument.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityStorage;
+
+  /**
+   * Entity storage mock which knows comment_type load method/argument.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $commentTypeStorage;
+
+  /**
+   * Entity view display mock.
+   *
+   * @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityViewDisplay;
+
+  /**
+   * Entity view display mock used for the 'full' display mode.
+   *
+   * @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityViewDisplayFull;
+
+  /**
+   * Comment type mock.
+   *
+   * @var \Drupal\comment\CommentTypeInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $commentType;
+
+  /**
+   * Field storage definition mock.
+   *
+   * @var \Drupal\Core\Field\FieldStorageDefinitionInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $fieldStorageDefinition;
+
+  /**
    * Comment manager mock.
    *
    * @var \Drupal\comment\CommentManagerInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -64,15 +114,44 @@ class CommentLinkBuilderTest extends UnitTestCase {
    * Prepares mocks for the test.
    */
   protected function setUp() {
+    $this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
+    $this->entityStorage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
+    $this->entityViewDisplay = $this->getMock('Drupal\Core\Entity\Display\EntityViewDisplayInterface');
+    $this->entityViewDisplayFull = $this->getMock('Drupal\Core\Entity\Display\EntityViewDisplayInterface');
+    $this->commentTypeStorage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
+    $this->commentType = $this->getMock('\Drupal\comment\CommentTypeInterface');
+    $this->entityViewDisplay =  $this->getMock('Drupal\Core\Entity\Display\EntityViewDisplayInterface');
+    $this->fieldStorageDefinition = $this->getMock('\Drupal\Core\Field\FieldStorageDefinitionInterface');
     $this->commentManager = $this->getMock('\Drupal\comment\CommentManagerInterface');
     $this->stringTranslation = $this->getStringTranslationStub();
     $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
     $this->currentUser = $this->getMock('\Drupal\Core\Session\AccountProxyInterface');
-    $this->commentLinkBuilder = new CommentLinkBuilder($this->currentUser, $this->commentManager, $this->moduleHandler, $this->stringTranslation);
+    $this->commentLinkBuilder = new CommentLinkBuilder($this->currentUser, $this->entityManager, $this->commentManager, $this->moduleHandler, $this->stringTranslation);
+    $this->fieldStorageDefinition->expects($this->any())
+      ->method('getSetting')
+      ->with('comment_type')
+      ->willReturn('comment');
+    $this->entityManager->expects($this->any())
+      ->method('getStorage')
+      ->will($this->returnValueMap(array(
+        array('entity_view_display', $this->entityStorage),
+        array('comment_type', $this->commentTypeStorage),
+      )));
+    $this->entityManager->expects($this->any())
+      ->method('getFieldStorageDefinitions')
+      ->with('node')
+      ->willReturn(array(
+        // The field name from getFields()
+        'comment' => $this->fieldStorageDefinition
+      ));
+    $this->commentTypeStorage->expects($this->any())
+      ->method('load')
+      ->willReturn($this->commentType);
     $this->commentManager->expects($this->any())
       ->method('getFields')
       ->with('node')
       ->willReturn(array(
+        // Key is a field name; we're choosing comment (and don't need a value).
         'comment' => array(),
       ));
     $this->commentManager->expects($this->any())
@@ -86,10 +165,15 @@ protected function setUp() {
   /**
    * Test the buildCommentedEntityLinks method.
    *
-   * @param \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject $node
-   *   Mock node.
-   * @param array $context
-   *   Context for the links.
+   * @param string $view_mode
+   *   The view mode for displaying the node.
+   * @param bool $node_has_field
+   *   TRUE if the node has the 'comment' field.
+   * @param int $comment_item_status
+   *   Status value of the 'comment' field in this particular node.
+   *   One of CommentItemInterface::OPEN|HIDDEN|CLOSED
+   * @param int $comment_count
+   *   Number of comments against the field.
    * @param bool $has_access_comments
    *   TRUE if the user has 'access comments' permission.
    * @param bool $history_exists
@@ -98,6 +182,13 @@ protected function setUp() {
    *   TRUE if the use has 'post comments' permission.
    * @param bool $is_anonymous
    *   TRUE if the user is anonymous.
+   * @param int|null $form_location
+   *   Form location setting for the current view mode.
+   *   One of CommentItemInterface::FORM_BELOW|FORM_SEPARATE_PAGE or NULL
+   * @param int|null $form_location_full
+   *   Form location setting for full view mode (will be equal to $form_location
+   *   if $view_mode is 'full').
+   *   One of CommentItemInterface::FORM_BELOW|FORM_SEPARATE_PAGE or NULL
    * @param array $expected
    *   Array of expected links keyed by link ID. Can be either string (link
    *   title) or array of link properties.
@@ -106,7 +197,9 @@ protected function setUp() {
    *
    * @covers ::buildCommentedEntityLinks
    */
-  public function testCommentLinkBuilder(NodeInterface $node, $context, $has_access_comments, $history_exists, $has_post_comments, $is_anonymous, $expected) {
+  public function testCommentLinkBuilder($view_mode, $node_has_field, $comment_item_status, $comment_count, $has_access_comments, $history_exists, $has_post_comments, $is_anonymous, $form_location, $form_location_full, $expected) {
+    $node = $this->getMockNode($node_has_field, $comment_item_status, $comment_count);
+
     $this->moduleHandler->expects($this->any())
       ->method('moduleExists')
       ->with('history')
@@ -123,7 +216,72 @@ public function testCommentLinkBuilder(NodeInterface $node, $context, $has_acces
     $this->currentUser->expects($this->any())
       ->method('isAnonymous')
       ->willReturn($is_anonymous);
+
+    if ($view_mode == 'full') {
+      $this->entityViewDisplay->expects($this->any())
+        ->method('getComponent')
+        ->willReturn(isset($form_location)
+          ? array(
+            'settings' => array(
+              'form_location' => $form_location,
+              // This only influences the page argument to the new-comments
+              // url, which we're not testing, so return static value.
+              'per_page' => 50
+            )
+          )
+          : NULL);
+      $this->entityStorage->expects($this->any())
+        ->method('load')
+        ->with($node->getEntityTypeId() . '.' . $node->bundle() . '.full')
+        ->willReturn($this->entityViewDisplay);
+    }
+    else {
+      // From the field formatter settings for the current display, the class
+      // should be using 'form_location'.
+      $this->entityViewDisplay->expects($this->any())
+        ->method('getComponent')
+        ->willReturn(isset($form_location)
+          ? array(
+            'settings' => array(
+              'form_location' => $form_location,
+              'per_page' => 50
+            )
+          )
+          : NULL);
+      // From the field formatter settings for the full display, the class
+      // should be using 'form_location'.
+      $this->entityViewDisplayFull->expects($this->any())
+        ->method('getComponent')
+        ->willReturn(isset($form_location_full)
+          ? array(
+            'settings' => array(
+              'form_location' => $form_location_full,
+              'per_page' => 50
+            )
+          )
+          : NULL);
+      $this->entityStorage->expects($this->any())
+        ->method('load')
+        ->willReturnMap(array(
+          array(
+            $node->getEntityTypeId() . '.' . $node->bundle() . '.full',
+            $this->entityViewDisplayFull
+          ),
+          array(
+            $node->getEntityTypeId() . '.' . $node->bundle() . '.' . $view_mode,
+            $this->entityViewDisplay
+          ),
+        ));
+    }
+    // This setting influences the page argument to the 'new comments' url,
+    // which we're not testing, so return static value.
+    $this->commentType->expects($this->any())
+      ->method('getThreadingMode')
+      ->willReturn(CommentTypeInterface::THREADING_MODE_THREADED);
+
+    $context = array('view_mode' => $view_mode);
     $links = $this->commentLinkBuilder->buildCommentedEntityLinks($node, $context);
+
     if (!empty($expected)) {
       if (!empty($links)) {
         foreach ($expected as $link => $detail) {
@@ -146,14 +304,12 @@ public function testCommentLinkBuilder(NodeInterface $node, $context, $has_acces
     else {
       $this->assertSame($links, $expected);
     }
-    if ($context['view_mode'] == 'rss' && $node->get('comment')->status) {
+    if ($view_mode == 'rss' && $node->get('comment')->status) {
       $found = FALSE;
-      if ($node->get('comment')->status) {
-        foreach ($node->rss_elements as $element) {
-          if ($element['key'] == 'comments') {
-            $found = TRUE;
-            break;
-          }
+      foreach ($node->rss_elements as $element) {
+        if ($element['key'] == 'comments') {
+          $found = TRUE;
+          break;
         }
       }
       $this->assertTrue($found);
@@ -167,23 +323,31 @@ public function getLinkCombinations() {
     $cases = array();
     // No links should be created if the entity doesn't have the field.
     $cases[] = array(
-      $this->getMockNode(FALSE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1),
-      array('view_mode' => 'teaser'),
+      'teaser',
+      FALSE,
+      CommentItemInterface::OPEN,
+      1,
       TRUE,
       TRUE,
       TRUE,
       TRUE,
+      CommentItemInterface::FORM_BELOW,
+      CommentItemInterface::FORM_BELOW,
       array(),
     );
     foreach (array('search_result', 'search_index', 'print') as $view_mode) {
       // Nothing should be output in these view modes.
       $cases[] = array(
-        $this->getMockNode(TRUE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1),
-        array('view_mode' => $view_mode),
+        $view_mode,
+        TRUE,
+        CommentItemInterface::OPEN,
+        1,
         TRUE,
         TRUE,
         TRUE,
         TRUE,
+        CommentItemInterface::FORM_BELOW,
+        CommentItemInterface::FORM_BELOW,
         array(),
       );
     }
@@ -194,7 +358,22 @@ public function getLinkCombinations() {
       'has_access_comments' => array(0, 1),
       'history_exists' => array(FALSE, TRUE),
       'has_post_comments'   => array(0, 1),
-      'form_location'            => array(CommentItemInterface::FORM_BELOW, CommentItemInterface::FORM_SEPARATE_PAGE),
+      // form_location is a field formatter setting which is checked on the
+      // current view mode (see below); NULL is used for "the field is hidden"
+      // (so no formatter settings) in this mode.
+      'form_location'            => array(
+        CommentItemInterface::FORM_BELOW,
+        CommentItemInterface::FORM_SEPARATE_PAGE,
+        NULL,
+      ),
+      // form_location_full is a field formatter setting which is checked on the
+      // full view mode; NULL is used for "the field is hidden" (so no formatter
+      // settings) in full mode.
+      'form_location_full' =>  array(
+        CommentItemInterface::FORM_BELOW,
+        CommentItemInterface::FORM_SEPARATE_PAGE,
+        NULL,
+      ),
       'comments'        => array(
         CommentItemInterface::OPEN,
         CommentItemInterface::CLOSED,
@@ -206,18 +385,34 @@ public function getLinkCombinations() {
     );
     $permutations = TestBase::generatePermutations($combinations);
     foreach ($permutations as $combination) {
+      if ($combination['view_mode'] == 'full'
+          && $combination['form_location'] !== $combination['form_location_full']) {
+        // Comment field in full mode is hidden AND visible at the same time;
+        // impossible.
+        continue;
+      }
+
       $case = array(
-        $this->getMockNode(TRUE, $combination['comments'], $combination['form_location'], $combination['comment_count']),
-        array('view_mode' => $combination['view_mode']),
+        $combination['view_mode'],
+        TRUE,
+        $combination['comments'],
+        $combination['comment_count'],
         $combination['has_access_comments'],
         $combination['history_exists'],
         $combination['has_post_comments'],
         $combination['is_anonymous'],
+        $combination['form_location'],
+        $combination['form_location_full'],
       );
       $expected = array();
-      // When comments are enabled in teaser mode, and comments exist, and the
-      // user has access - we can output the comment count.
-      if ($combination['comments'] && $combination['view_mode'] == 'teaser' && $combination['comment_count'] && $combination['has_access_comments']) {
+      // When comments exist, you're viewing teaser mode and comments are
+      // visible in 'full' view mode and the user has access, we can output the
+      // comment count with link.
+      if ($combination['view_mode'] == 'teaser'
+          && $combination['form_location_full'] !== NULL
+          && $combination['comments'] != CommentItemInterface::HIDDEN
+          && $combination['comment_count']
+          && $combination['has_access_comments']) {
         $expected['comment-comments'] = '1 comment';
         // And if history module exists, we can show a 'new comments' link.
         if ($combination['history_exists']) {
@@ -230,13 +425,30 @@ public function getLinkCombinations() {
         if ($combination['comments'] == CommentItemInterface::OPEN) {
           // And the user has post-comments permission.
           if ($combination['has_post_comments']) {
-            // If the view mode is teaser, or the user can access comments and
-            // comments exist or the form is on a separate page.
-            if ($combination['view_mode'] == 'teaser' || ($combination['has_access_comments'] && $combination['comment_count']) || $combination['form_location'] == CommentItemInterface::FORM_SEPARATE_PAGE) {
+            // Show "add comment" link, unless the form is directly below it
+            // (that is, if there are no comments displayed in between).
+            if ($combination['form_location'] !== CommentItemInterface::FORM_BELOW
+                || ($combination['has_access_comments']
+                    && $combination['comment_count'])) {
               // There should be a add comment link.
               $expected['comment-add'] = array('title' => 'Add new comment');
-              if ($combination['form_location'] == CommentItemInterface::FORM_BELOW) {
-                // On the same page.
+              if ($combination['form_location'] === CommentItemInterface::FORM_BELOW) {
+                // On the same page, which is not the full node page.
+                // @todo see CommentLinkBuilder.
+                if (\Drupal::hasRequest()) {
+                  $request = \Drupal::request();
+                }
+                else {
+                  $request = Request::createFromGlobals();
+                }
+                $links['comment-add']['url'] = $request->getPathInfo() == '/'
+                    ? Url::fromRoute('<front>') : Url::fromRoute('<current>');
+              }
+              elseif ($combination['form_location'] === CommentItemInterface::FORM_BELOW
+                      || ($combination['form_location'] === NULL
+                          && $combination['form_location_full'] === CommentItemInterface::FORM_BELOW)) {
+                // On the node page. (Linked from the same page or from another
+                // view mode.)
                 $expected['comment-add']['url'] = Url::fromRoute('node.view');
               }
               else {
@@ -246,7 +458,7 @@ public function getLinkCombinations() {
             }
           }
           elseif ($combination['is_anonymous']) {
-            // Anonymous users get the forbidden message if the can't post
+            // Anonymous users get the forbidden message if they can't post
             // comments.
             $expected['comment-forbidden'] = "Can't let you do that Dave.";
           }
@@ -266,17 +478,15 @@ public function getLinkCombinations() {
    *   TRUE if the node has the 'comment' field.
    * @param int $comment_status
    *   One of CommentItemInterface::OPEN|HIDDEN|CLOSED
-   * @param int $form_location
-   *   One of CommentItemInterface::FORM_BELOW|FORM_SEPARATE_PAGE
    * @param int $comment_count
    *   Number of comments against the field.
    *
    * @return \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject
    *   Mock node for testing.
    */
-  protected function getMockNode($has_field, $comment_status, $form_location, $comment_count) {
+  protected function getMockNode($has_field, $comment_status, $comment_count) {
     $node = $this->getMock('\Drupal\node\NodeInterface');
-    $node->expects($this->once())
+    $node->expects($this->any())
       ->method('hasField')
       ->willReturn($has_field);
 
@@ -294,10 +504,6 @@ protected function getMockNode($has_field, $comment_status, $form_location, $com
       ->willReturn($field_item);
 
     $field_definition = $this->getMock('\Drupal\Core\Field\FieldDefinitionInterface');
-    $field_definition->expects($this->any())
-      ->method('getSetting')
-      ->with('form_location')
-      ->willReturn($form_location);
     $node->expects($this->any())
       ->method('getFieldDefinition')
       ->with('comment')
@@ -312,6 +518,10 @@ protected function getMockNode($has_field, $comment_status, $form_location, $com
       ->willReturn('node');
 
     $node->expects($this->any())
+      ->method('bundle')
+      ->willReturn('article');
+
+    $node->expects($this->any())
       ->method('id')
       ->willReturn(1);
 
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 2cf0c53..45dda85 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\comment\CommentInterface;
+use Drupal\comment\Entity\CommentType;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Entity\EntityInterface;
@@ -405,6 +406,10 @@ function forum_theme_suggestions_forums(array $variables) {
  */
 function template_preprocess_forums(&$variables) {
   $variables['tid'] = $variables['term']->id();
+  $display = entity_get_display('node', 'forum', 'full');
+  $settings = $display->getComponent('comment_forum')['settings'];
+  $field_definition = \Drupal::entityManager()->getFieldStorageDefinitions('node')['comment_forum'];
+  $comment_type = CommentType::load($field_definition->getSetting('comment_type'));
   if ($variables['forums_defined'] = count($variables['forums']) || count($variables['parents'])) {
     if (!empty($variables['forums'])) {
       $variables['forums'] = array(
@@ -471,7 +476,7 @@ function template_preprocess_forums(&$variables) {
 
         if ($topic->new_replies) {
           $page_number = \Drupal::entityManager()->getStorage('comment')
-            ->getNewCommentPageNumber($topic->comment_count, $topic->new_replies, $topic, 'comment_forum');
+            ->getNewCommentPageNumber($topic->comment_count, $topic->new_replies, $topic, $comment_type->getThreadingMode(), $settings['per_page'], 'comment_forum');
           $query = $page_number ? array('page' => $page_number) : NULL;
           $variables['topics'][$id]->new_text = \Drupal::translation()->formatPlural($topic->new_replies, '1 new post<span class="visually-hidden"> in topic %title</span>', '@count new posts<span class="visually-hidden"> in topic %title</span>', array('%title' => $variables['topics'][$id]->label()));
           $variables['topics'][$id]->new_url = \Drupal::url('entity.node.canonical', ['node' => $topic->id()], ['query' => $query, 'fragment' => 'new']);
diff --git a/core/modules/rdf/src/Tests/CommentAttributesTest.php b/core/modules/rdf/src/Tests/CommentAttributesTest.php
index e678de2..6abe334 100644
--- a/core/modules/rdf/src/Tests/CommentAttributesTest.php
+++ b/core/modules/rdf/src/Tests/CommentAttributesTest.php
@@ -8,7 +8,7 @@
 namespace Drupal\rdf\Tests;
 
 use Drupal\comment\CommentInterface;
-use Drupal\comment\CommentManagerInterface;
+use Drupal\comment\CommentTypeInterface;
 use Drupal\comment\Tests\CommentTestBase;
 use Drupal\user\RoleInterface;
 
@@ -54,7 +54,7 @@ protected function setUp() {
     $this->setCommentPreview(DRUPAL_OPTIONAL);
     $this->setCommentForm(TRUE);
     $this->setCommentSubject(TRUE);
-    $this->setCommentSettings('comment_default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.');
+    $this->setThreadingMode(CommentTypeInterface::THREADING_MODE_THREADED);
 
     // Prepares commonly used URIs.
     $this->baseUri = \Drupal::url('<front>', [], ['absolute' => TRUE]);
