diff --git a/core/lib/Drupal/Core/Field/FieldItemBase.php b/core/lib/Drupal/Core/Field/FieldItemBase.php
index 33ec95cb6ff9311b1f6fba890cda1ebbe22f2f17..39b9412745f602b7d5bc97719ba7d49522350e0f 100644
--- a/core/lib/Drupal/Core/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Field/FieldItemBase.php
@@ -243,7 +243,7 @@ public function deleteRevision() { }
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     return array();
   }
 
diff --git a/core/lib/Drupal/Core/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Field/FieldItemInterface.php
index 3943bad553cd2745fa391750ed2cbb119d269242..693a39a29f0d33bd018cc40ed2695e8fc615909b 100644
--- a/core/lib/Drupal/Core/Field/FieldItemInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php
@@ -252,7 +252,7 @@ public static function defaultInstanceSettings();
    * @return
    *   The form definition for the field settings.
    */
-  public function settingsForm(array $form, array &$form_state, $has_data);
+  public function settingsForm(array &$form, array &$form_state, $has_data);
 
   /**
    * Returns a form for the instance-level settings.
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
index 30d33c5afe10fb1fe4afc998ffcc3af2a5311f5b..10d03b3aa6a04d7c0a620a4f9b1e8114df127cb0 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
@@ -63,7 +63,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $element = array();
     $settings = $this->getSettings();
 
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index 0c35aaecc37d9b215b78ebf2a06043458f4fb75d..391a2555e18b090c5d80a7c907a206c094cedfbe 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -5,6 +5,8 @@
  * Install, update and uninstall functions for the Comment module.
  */
 
+use Drupal\field\Entity\FieldConfig;
+
 /**
  * Implements hook_uninstall().
  */
@@ -49,12 +51,12 @@ function comment_schema() {
         'length' => 255,
         'description' => 'The entity_type of the entity to which this comment is a reply.',
       ),
-      'field_id' => array(
+      'field_name' => array(
         'type' => 'varchar',
         'not null' => TRUE,
-        'default' => 'node__comment',
-        'length' => 255,
-        'description' => 'The field_id of the field that was used to add this comment.',
+        'default' => '',
+        'length' => FieldConfig::NAME_MAX_LENGTH,
+        'description' => 'The field_name of the field that was used to add this comment.',
       ),
       'cid' => array(
         'type' => 'int',
@@ -89,7 +91,7 @@ function comment_schema() {
         'description' => 'The total number of comments on this entity.',
       ),
     ),
-    'primary key' => array('entity_id', array('entity_type', 32), array('field_id', 32)),
+    'primary key' => array('entity_id', 'entity_type', 'field_name'),
     'indexes' => array(
       'last_comment_timestamp' => array('last_comment_timestamp'),
       'comment_count' => array('comment_count'),
diff --git a/core/modules/comment/comment.local_actions.yml b/core/modules/comment/comment.local_actions.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0f65c768f64931ab2c81d2e12f357cf30bb43d2a
--- /dev/null
+++ b/core/modules/comment/comment.local_actions.yml
@@ -0,0 +1,5 @@
+comment_type_add:
+  route_name: comment.type_add
+  title: 'Add comment type'
+  appears_on:
+    - comment.type_list
diff --git a/core/modules/comment/comment.local_tasks.yml b/core/modules/comment/comment.local_tasks.yml
index 8826d1d70040b18de5851b2f5d08bc6608f5c2ad..ecf92e9f04cca65b62112afbe5b86d6a3a8c426b 100644
--- a/core/modules/comment/comment.local_tasks.yml
+++ b/core/modules/comment/comment.local_tasks.yml
@@ -29,3 +29,9 @@ comment.admin_approval:
   class: Drupal\comment\Plugin\Menu\LocalTask\UnapprovedComments
   parent_id: comment.admin
   weight: 1
+
+# Default tab for comment type editing.
+comment.type_edit:
+  title: 'Edit'
+  route_name: comment.type_edit
+  base_route: comment.type_edit
diff --git a/core/modules/comment/comment.menu_links.yml b/core/modules/comment/comment.menu_links.yml
index 7f0af7805aa93af6f34c77d92b504510f01a817c..e4d4488b58bcd595d77224edce4aa613f9b568e2 100644
--- a/core/modules/comment/comment.menu_links.yml
+++ b/core/modules/comment/comment.menu_links.yml
@@ -3,8 +3,8 @@ comment.admin:
   route_name: comment.admin
   parent: system.admin_content
   description: 'List and edit site comments and the comment approval queue.'
-comment.bundle_list:
-  title: 'Comment forms'
-  route_name: comment.bundle_list
+comment.type_list:
+  title: 'Comment types'
+  route_name: comment.type_list
   parent: system.admin_structure
-  description: 'Manage fields and displays settings for comment forms.'
+  description: 'Manage form and displays settings of comments.'
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 09bbaa92da98089c50b20fad05dfd956b681cb9b..d3522acfbb04198108d9aec7fbc8dc45e2ac7351 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -12,6 +12,7 @@
 
 use Drupal\comment\CommentInterface;
 use Drupal\comment\Entity\Comment;
+use Drupal\comment\Entity\CommentType;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\ContentEntityInterface;
@@ -21,6 +22,7 @@
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Url;
+use Drupal\field\Entity\FieldConfig;
 use Drupal\field\FieldInstanceConfigInterface;
 use Drupal\field\FieldConfigInterface;
 use Drupal\file\FileInterface;
@@ -93,41 +95,12 @@ function comment_help($route_name, Request $request) {
       $output .= '</dl>';
       return $output;
 
-    case 'comment.bundle_list':
-      $output = '<p>' . t('This page provides a list of all comment forms on the site and allows you to manage the fields, form and display settings for each.') . '</p>';
+    case 'comment.type_list':
+      $output = '<p>' . t('This page provides a list of all comment types on the site and allows you to manage the fields, form and display settings for each.') . '</p>';
       return $output;
   }
 }
 
-/**
- * Implements hook_entity_bundle_info().
- */
-function comment_entity_bundle_info() {
-  $bundles = array();
-  $ids = \Drupal::entityQuery('field_config')
-    ->condition('type', 'comment')
-    ->execute();
-  $config_factory = \Drupal::configFactory();
-  foreach ($ids as $id) {
-    // @todo: We can not rely on the field map here, so we need to manually look
-    //   for a matching field instance to use for the label. Remove this in
-    //   https://drupal.org/node/2228763.
-    list($entity_type_id, $field_name) = explode('.', $id);
-    $instance_ids = $config_factory->listAll('field.instance.' . $entity_type_id . '.');
-    // Look for an instance for this field.
-    foreach ($instance_ids as $instance_id) {
-      $instance_field_name = substr($instance_id, strrpos($instance_id, '.') + 1);
-      if ($instance_field_name == $field_name) {
-        $config = \Drupal::config($instance_id);
-        $bundles['comment'][$entity_type_id . '__' . $field_name] = array(
-          'label' => $config->get('label'),
-        );
-      }
-    }
-  }
-  return $bundles;
-}
-
 /**
  * Entity URI callback.
  */
@@ -146,23 +119,21 @@ function comment_uri(CommentInterface $comment) {
  */
 function comment_entity_extra_field_info() {
   $return = array();
-  foreach (\Drupal::service('comment.manager')->getAllFields() as $entity_type => $fields) {
-    foreach ($fields as $field_name => $field_info) {
-      $return['comment'][$entity_type . '__' . $field_name] = array(
-        'form' => array(
-          'author' => array(
-            'label' => t('Author'),
-            'description' => t('Author textfield'),
-            'weight' => -2,
-          ),
-          'subject' => array(
-            'label' => t('Subject'),
-            'description' => t('Subject textfield'),
-            'weight' => -1,
-          ),
+  foreach (CommentType::loadMultiple() as $comment_type) {
+    $return['comment'][$comment_type->id] = array(
+      'form' => array(
+        'author' => array(
+          'label' => t('Author'),
+          'description' => t('Author textfield'),
+          'weight' => -2,
         ),
-      );
-    }
+        'subject' => array(
+          'label' => t('Subject'),
+          'description' => t('Subject textfield'),
+          'weight' => -1,
+        ),
+      ),
+    );
   }
 
   return $return;
@@ -196,15 +167,6 @@ function comment_count_unpublished() {
   return t('Unapproved comments (@count)', array('@count' => $count));
 }
 
-/**
- * Implements hook_ENTITY_TYPE_insert() for 'field_instance_config'.
- */
-function comment_field_instance_config_insert(FieldInstanceConfigInterface $instance) {
-  if ($instance->getType() == 'comment' && !$instance->isSyncing()) {
-    \Drupal::service('comment.manager')->addBodyField($instance->entity_type, $instance->getName());
-  }
-}
-
 /**
  * Implements hook_ENTITY_TYPE_create() for 'field_instance_config'.
  */
@@ -237,16 +199,6 @@ function comment_field_instance_config_update(FieldInstanceConfigInterface $inst
   }
 }
 
-/**
- * Implements hook_ENTITY_TYPE_delete() for 'field_config'.
- */
-function comment_field_config_delete(FieldConfigInterface $field) {
-  if ($field->getType() == 'comment') {
-    // Delete all fields and displays attached to the comment bundle.
-    entity_invoke_bundle_hook('delete', 'comment', $field->entity_type . '__' . $field->getName());
-  }
-}
-
 /**
  * Implements hook_ENTITY_TYPE_insert() for 'field_config'.
  */
@@ -257,8 +209,6 @@ function comment_field_config_insert(FieldConfigInterface $field) {
     if (!_comment_entity_uses_integer_id($entity_type_id)) {
       throw new \UnexpectedValueException('You cannot attach a comment field to an entity with a non-integer ID field');
     }
-    // Delete all fields and displays attached to the comment bundle.
-    entity_invoke_bundle_hook('insert', 'comment', $entity_type_id . '__' . $field->getName());
   }
 }
 
@@ -268,9 +218,9 @@ function comment_field_config_insert(FieldConfigInterface $field) {
 function comment_field_instance_config_delete(FieldInstanceConfigInterface $instance) {
   if ($instance->getType() == 'comment') {
     // Delete all comments that used by the entity bundle.
-    $comments = db_query("SELECT cid FROM {comment} WHERE entity_type = :entity_type AND field_id = :field_id", array(
+    $comments = db_query("SELECT cid FROM {comment} WHERE entity_type = :entity_type AND field_name = :field_name", array(
       ':entity_type' => $instance->getEntityTypeId(),
-      ':field_id' => $instance->getEntityTypeId() . '__' . $instance->getName(),
+      ':field_name' => $instance->getName(),
     ))->fetchCol();
     entity_delete_multiple('comment', $comments);
   }
@@ -284,6 +234,10 @@ function comment_permission() {
     'administer comments' => array(
       'title' => t('Administer comments and comment settings'),
     ),
+    'administer comment types' => array(
+      'title' => t('Administer comment types and settings'),
+      'restrict access' => TRUE,
+    ),
     'access comments' => array(
       'title' => t('View comments'),
     ),
@@ -338,7 +292,7 @@ function comment_new_page_count($num_comments, $new_replies, ContentEntityInterf
       ->fields('comment', array('thread'))
       ->condition('entity_id', $entity->id())
       ->condition('entity_type', $entity->getEntityTypeId())
-      ->condition('field_id', $entity->getEntityTypeId() . '__' . $field_name)
+      ->condition('field_name', $field_name)
       ->condition('status', CommentInterface::PUBLISHED)
       ->orderBy('created', 'DESC')
       ->orderBy('cid', 'DESC')
@@ -360,11 +314,11 @@ function comment_new_page_count($num_comments, $new_replies, ContentEntityInterf
     // Find the number of the first comment of the first unread thread.
     $count = db_query('SELECT COUNT(*) FROM {comment} WHERE entity_id = :entity_id
                       AND entity_type = :entity_type
-                      AND field_id = :field_id
+                      AND field_name = :field_name
                       AND status = :status AND SUBSTRING(thread, 1, (LENGTH(thread) - 1)) < :thread', array(
       ':status' => CommentInterface::PUBLISHED,
       ':entity_id' => $entity->id(),
-      ':field_id' => $entity->getEntityTypeId() . '__' . $field_name,
+      ':field_name' => $field_name,
       ':entity_type' => $entity->getEntityTypeId(),
       ':thread' => $first_thread,
     ))->fetchField();
@@ -578,10 +532,12 @@ function comment_node_view_alter(array &$build, EntityInterface $node, EntityVie
  *   The renderable array for the comment addition form.
  */
 function comment_add(EntityInterface $entity, $field_name = 'comment', $pid = NULL) {
+  $field = Fieldconfig::loadByName($entity->getEntityTypeId(), $field_name);
   $values = array(
     'entity_type' => $entity->getEntityTypeId(),
     'entity_id' => $entity->id(),
-    'field_id' => $entity->getEntityTypeId() . '__' . $field_name,
+    'field_name' => $field_name,
+    'comment_type' => $field->getSetting('bundle'),
     'pid' => $pid,
   );
   $comment = entity_create('comment', $values);
@@ -670,7 +626,7 @@ function comment_get_thread(EntityInterface $entity, $field_name, $mode, $commen
   $query
     ->condition('c.entity_id', $entity->id())
     ->condition('c.entity_type', $entity->getEntityTypeId())
-    ->condition('c.field_id', $entity->getEntityTypeId() . '__' . $field_name)
+    ->condition('c.field_name', $field_name)
     ->addTag('entity_access')
     ->addTag('comment_filter')
     ->addMetaData('base_table', 'comment')
@@ -683,7 +639,7 @@ function comment_get_thread(EntityInterface $entity, $field_name, $mode, $commen
   $count_query
     ->condition('c.entity_id', $entity->id())
     ->condition('c.entity_type', $entity->getEntityTypeId())
-    ->condition('c.field_id', $entity->getEntityTypeId() . '__' . $field_name)
+    ->condition('c.field_name', $field_name)
     ->addTag('entity_access')
     ->addTag('comment_filter')
     ->addMetaData('base_table', 'comment')
@@ -782,21 +738,6 @@ function comment_view_multiple($comments, $view_mode = 'full', $langcode = NULL)
   return entity_view_multiple($comments, $view_mode, $langcode);
 }
 
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function comment_form_field_ui_field_instance_edit_form_alter(&$form, $form_state) {
-  if ($form['#field']->getType() == 'comment') {
-    // Collect translation settings.
-    if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
-      array_unshift($form['#submit'], 'comment_translation_configuration_element_submit');
-    }
-
-    // Hide required checkbox.
-    $form['instance']['required']['#access'] = FALSE;
-  }
-}
-
 /**
  * Implements hook_form_FORM_ID_alter().
  */
@@ -844,28 +785,6 @@ function comment_form_field_ui_field_edit_form_alter(&$form, $form_state) {
   }
 }
 
-/**
- * Form submission handler for field_ui_field_edit_form().
- *
- * This handles the comment translation settings added by
- * _comment_field_instance_settings_form_process().
- *
- * @see _comment_field_instance_settings_form_process()
- */
-function comment_translation_configuration_element_submit($form, &$form_state) {
-  // The comment translation settings form element is embedded into the instance
-  // settings form. Hence we need to provide to the regular submit handler a
-  // manipulated form state to make it process comment settings instead of the
-  // host entity.
-  $key = 'language_configuration';
-  $comment_form_state = array(
-    'content_translation' => array('key' => $key),
-    'language' => array($key => array('entity_type' => 'comment', 'bundle' => $form['#field']->name)),
-    'values' => array($key => array('content_translation' => $form_state['values']['content_translation'])),
-  );
-  content_translation_language_configuration_element_submit($form, $comment_form_state);
-}
-
 /**
  * Implements hook_entity_load().
  *
@@ -884,14 +803,11 @@ function comment_entity_load($entities, $entity_type) {
   // comment statistics properties, which are defined on each CommentItem field.
   $result = \Drupal::service('comment.statistics')->read($entities, $entity_type);
   foreach ($result as $record) {
-    $parts = explode('__', $record->field_id, 2);
-    list(, $field_name) = $parts;
-
     // Skip fields that entity does not have.
-    if (!$entities[$record->entity_id]->hasField($field_name)) {
+    if (!$entities[$record->entity_id]->hasField($record->field_name)) {
       continue;
     }
-    $comment_statistics = $entities[$record->entity_id]->get($field_name);
+    $comment_statistics = $entities[$record->entity_id]->get($record->field_name);
     $comment_statistics->cid = $record->cid;
     $comment_statistics->last_comment_timestamp = $record->last_comment_timestamp;
     $comment_statistics->last_comment_name = $record->last_comment_name;
@@ -1166,7 +1082,7 @@ function comment_num_new($entity_id, $entity_type, $field_name = NULL, $timestam
       ->condition('c.created', $timestamp, '>');
     if ($field_name) {
       // Limit to a particular field.
-      $query->condition('c.field_id', $entity_type . '__' . $field_name);
+      $query->condition('c.field_name', $field_name);
     }
 
     return $query->execute()
@@ -1198,7 +1114,7 @@ function comment_get_display_ordinal($cid, FieldDefinitionInterface $field_defin
   // Count how many comments (c1) are before $cid (c2) in display order. This is
   // the 0-based display ordinal.
   $query = db_select('comment', 'c1');
-  $query->innerJoin('comment', 'c2', 'c2.entity_id = c1.entity_id AND c2.entity_type = c1.entity_type AND c2.field_id = c1.field_id');
+  $query->innerJoin('comment', 'c2', 'c2.entity_id = c1.entity_id AND c2.entity_type = c1.entity_type AND c2.field_name = c1.field_name');
   $query->addExpression('COUNT(*)', 'count');
   $query->condition('c2.cid', $cid);
   if (!user_access('administer comments')) {
diff --git a/core/modules/comment/comment.routing.yml b/core/modules/comment/comment.routing.yml
index 1a6ac597e2f1fa2e393d8fff8a11310ba1f8e336..04b4b7e3ae6dd9c20303478a638cfd90db201ce9 100644
--- a/core/modules/comment/comment.routing.yml
+++ b/core/modules/comment/comment.routing.yml
@@ -66,20 +66,6 @@ comment.new_comments_node_links:
   requirements:
     _permission: 'access content'
 
-comment.bundle_list:
-  path: '/admin/structure/comments'
-  defaults:
-    _content: '\Drupal\comment\Controller\AdminController::overviewBundles'
-    _title: 'Comment forms'
-  requirements:
-    _permission: 'administer comments'
-
-# This route is only used by Field UI.
-comment.bundle:
-  path: '/admin/structure/comments/manage/{bundle}'
-  requirements:
-    _access: 'FALSE'
-
 comment.node_redirect:
   path: '/comment/{node}/reply'
   defaults:
@@ -87,3 +73,43 @@ comment.node_redirect:
   requirements:
     _entity_access: 'node.view'
     _module_dependencies: 'node'
+
+comment.type_list:
+  path: '/admin/structure/comment'
+  defaults:
+    _entity_list: 'comment_type'
+    _title: 'Comment types'
+  requirements:
+    _permission: 'administer comment types'
+  options:
+    _admin_route: TRUE
+
+comment.type_delete:
+  path: '/admin/structure/comment/manage/{comment_type}/delete'
+  defaults:
+    _entity_form: 'comment_type.delete'
+    _title: 'Delete'
+  requirements:
+    _entity_access: 'comment_type.delete'
+  options:
+    _admin_route: TRUE
+
+comment.type_add:
+  path: '/admin/structure/comment/types/add'
+  defaults:
+    _entity_form: 'comment_type.add'
+    _title: 'Add'
+  requirements:
+    _permission: 'administer comment types'
+  options:
+    _admin_route: TRUE
+
+comment.type_edit:
+  path: '/admin/structure/comment/manage/{comment_type}'
+  defaults:
+    _entity_form: 'comment_type.edit'
+    _title: 'Edit'
+  requirements:
+    _entity_access: 'comment_type.update'
+  options:
+    _admin_route: TRUE
diff --git a/core/modules/comment/comment.services.yml b/core/modules/comment/comment.services.yml
index 13846b11f35cd65dc46aadc32bfa39e729c6ad46..b0fc2ad2500be8ce4965f0c2c5bcf10a2873a846 100644
--- a/core/modules/comment/comment.services.yml
+++ b/core/modules/comment/comment.services.yml
@@ -12,9 +12,3 @@ services:
   comment.statistics:
     class: Drupal\comment\CommentStatistics
     arguments: ['@database', '@current_user', '@entity.manager', '@state']
-
-  comment.route_enhancer:
-      class: Drupal\comment\Routing\CommentBundleEnhancer
-      arguments: ['@entity.manager']
-      tags:
-        - { name: route_enhancer}
diff --git a/core/modules/comment/comment.views.inc b/core/modules/comment/comment.views.inc
index dddf7ef292e88bcd4a986288c1412311e3e51ed5..aa6008c60a325e338f464c46c30c1022cc88363e 100644
--- a/core/modules/comment/comment.views.inc
+++ b/core/modules/comment/comment.views.inc
@@ -332,9 +332,26 @@ function comment_views_data() {
     ),
   );
 
-  $data['comment']['field_id'] = array(
-    'title' => t('Comment field id'),
-    'help' => t('The Field id from which the comment originated.'),
+  $data['comment']['field_name'] = array(
+    'title' => t('Comment field name'),
+    'help' => t('The Field name from which the comment originated.'),
+    'field' => array(
+      'id' => 'standard',
+    ),
+    'filter' => array(
+      'id' => 'string',
+    ),
+    'argument' => array(
+      'id' => 'string',
+    ),
+    'sort' => array(
+      'id' => 'standard',
+    ),
+  );
+
+  $data['comment']['comment_type'] = array(
+    'title' => t('Comment type'),
+    'help' => t('The comment type for this comment.'),
     'field' => array(
       'id' => 'standard',
     ),
@@ -567,9 +584,9 @@ function comment_views_data() {
       'id' => 'standard',
     ),
   );
-  $data['comment_entity_statistics']['field_id'] = array(
-    'title' => t('Comment field ID'),
-    'help' => t('The field ID from which the comment originated.'),
+  $data['comment_entity_statistics']['field_name'] = array(
+    'title' => t('Comment field name'),
+    'help' => t('The field name from which the comment originated.'),
     'field' => array(
       'id' => 'standard',
     ),
@@ -666,8 +683,8 @@ function comment_views_data_alter(&$data) {
                 'value' => $entity_type_id,
               ),
               array(
-                'field' => 'field_id',
-                'value' => $entity_type_id . '.' . $field_name,
+                'field' => 'field_name',
+                'value' => $field_name,
               ),
             ),
           ),
diff --git a/core/modules/comment/config/schema/comment.schema.yml b/core/modules/comment/config/schema/comment.schema.yml
index 3b322b20c4b939c9427a3967e805ad9922caa256..2ad9b13b17343fe30d3a640dcdf48c1cccbac98d 100644
--- a/core/modules/comment/config/schema/comment.schema.yml
+++ b/core/modules/comment/config/schema/comment.schema.yml
@@ -43,6 +43,16 @@ action.configuration.comment_unpublish_action:
   type: action_configuration_default
   label: 'Unpublish comment configuration'
 
+comment.type.*:
+  type: config_entity
+  label: 'Comment type settings'
+  mapping:
+    target_entity_type_id:
+      type: string
+      label: 'Target Entity Type ID'
+    description:
+      type: text
+      label: 'Description'
 
 field.comment.settings:
   type: sequence
diff --git a/core/modules/comment/src/CommentFieldNameItem.php b/core/modules/comment/src/CommentFieldNameItem.php
deleted file mode 100644
index 94b858709dcd29cec66cb67c3ce09a744f2b1514..0000000000000000000000000000000000000000
--- a/core/modules/comment/src/CommentFieldNameItem.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\comment\CommentFieldNameItem.
- */
-
-namespace Drupal\comment;
-
-use Drupal\Core\Field\FieldStorageDefinitionInterface;
-use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
-use Drupal\Core\TypedData\DataDefinition;
-
-/**
- * The field item for the 'fieldname' field.
- */
-class CommentFieldNameItem extends StringItem {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
-    $properties['value'] = DataDefinition::create('string')
-      ->setLabel(t('String value'))
-      ->setClass('\Drupal\comment\CommentFieldNameValue')
-      ->setComputed(TRUE);
-
-    return $properties;
-  }
-
-}
diff --git a/core/modules/comment/src/CommentFieldNameValue.php b/core/modules/comment/src/CommentFieldNameValue.php
deleted file mode 100644
index 0190b8d6a795488c95f7f9ec03d68d413ee73178..0000000000000000000000000000000000000000
--- a/core/modules/comment/src/CommentFieldNameValue.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\comment\CommentFieldNameValue.
- */
-
-namespace Drupal\comment;
-
-use Drupal\Core\TypedData\TypedData;
-use Drupal\Core\TypedData\ReadOnlyException;
-use InvalidArgumentException;
-
-/**
- * A computed property for the string value of the field_name field.
- */
-class CommentFieldNameValue extends TypedData {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getValue() {
-    if (!isset($this->value)) {
-      if (!isset($this->parent)) {
-        throw new InvalidArgumentException('Computed properties require context for computation.');
-      }
-      $field = $this->parent->getParent();
-      $entity = $field->getParent();
-      // Field id is of the form {entity_type}__{field_name}. We set the
-      // optional limit param to explode() in case the user adds a field with __
-      // in the name.
-      $parts = explode('__', $entity->getFieldId(), 2);
-      if ($parts && count($parts) == 2) {
-        $this->value = end($parts);
-      }
-    }
-    return $this->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setValue($value, $notify = TRUE) {
-    if (isset($value)) {
-      $this->field_name = $value;
-      // Also set the field id.
-      $field = $this->parent->getParent();
-      $entity = $field->getParent();
-      $entity->field_id = $entity->getCommentedEntityTypeId() . '__' . $value;
-    }
-  }
-
-}
diff --git a/core/modules/comment/src/CommentForm.php b/core/modules/comment/src/CommentForm.php
index 1c9b0855f140f856eba1ba0f37eb198a480d8ec8..b804aaa472152942b8257d16b0ac8c438ea125f6 100644
--- a/core/modules/comment/src/CommentForm.php
+++ b/core/modules/comment/src/CommentForm.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -156,6 +157,15 @@ public function form(array $form, array &$form_state) {
       $form['author']['name']['#account'] = $this->currentUser;
     }
 
+    $language_configuration = \Drupal::moduleHandler()->invoke('language', 'get_default_configuration', array('comment', $comment->getTypeId()));
+    $form['langcode'] = array(
+      '#title' => t('Language'),
+      '#type' => 'language_select',
+      '#default_value' => $comment->getUntranslated()->language()->id,
+      '#languages' => Language::STATE_ALL,
+      '#access' => isset($language_configuration['language_show']) && $language_configuration['language_show'],
+    );
+
     // Add author email and homepage fields depending on the current user.
     $form['author']['mail'] = array(
       '#type' => 'email',
@@ -211,13 +221,6 @@ public function form(array $form, array &$form_state) {
       '#value' => ($comment->id() ? !$comment->getOwnerId() : $this->currentUser->isAnonymous()),
     );
 
-    // Add internal comment properties.
-    $original = $comment->getUntranslated();
-    foreach (array('cid', 'pid', 'entity_id', 'entity_type', 'field_id', 'uid', 'langcode') as $key) {
-      $key_name = key($comment->$key->getFieldDefinition()->getPropertyDefinitions());
-      $form[$key] = array('#type' => 'value', '#value' => $original->$key->{$key_name});
-    }
-
     return parent::form($form, $form_state, $comment);
   }
 
@@ -263,8 +266,9 @@ protected function actions(array $form, array &$form_state) {
    */
   public function validate(array $form, array &$form_state) {
     parent::validate($form, $form_state);
+    $entity = $this->entity;
 
-    if (!empty($form_state['values']['cid'])) {
+    if (!$entity->isNew()) {
       // Verify the name in case it is being changed from being anonymous.
       $accounts = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $form_state['values']['name']));
       $account = reset($accounts);
@@ -364,8 +368,8 @@ public function preview(array &$form, array &$form_state) {
    * Overrides Drupal\Core\Entity\EntityForm::save().
    */
   public function save(array $form, array &$form_state) {
-    $entity = entity_load($form_state['values']['entity_type'], $form_state['values']['entity_id']);
     $comment = $this->entity;
+    $entity = $comment->getCommentedEntity();
     $field_name = $comment->getFieldName();
     $uri = $entity->urlInfo();
 
diff --git a/core/modules/comment/src/CommentInterface.php b/core/modules/comment/src/CommentInterface.php
index 347b1f68f5de92b8daa591922c42d9481f44a77f..d2fd09af081005998f88cc61289c7d741eb8b585 100644
--- a/core/modules/comment/src/CommentInterface.php
+++ b/core/modules/comment/src/CommentInterface.php
@@ -66,25 +66,16 @@ public function getCommentedEntityId();
    */
   public function getCommentedEntityTypeId();
 
-  /**
-   * Returns the field ID of the comment field the comment is attached to.
-   *
-   * @return string
-   *   The field identifier of the field the comment is attached to.
-   */
-  public function getFieldId();
-
   /**
    * Sets the field ID for which this comment is attached.
    *
-   * @param string $field_id
-   *   The field identifier, usually formatted: {entity_type}__{field_name},
-   *   for example, node__comment.
+   * @param string $field_name
+   *   The field name through which the comment was added.
    *
    * @return $this
    *   The class instance that this method is called on.
    */
-  public function setFieldId($field_id);
+  public function setFieldName($field_name);
 
   /**
    * Returns the name of the field the comment is attached to.
@@ -258,4 +249,12 @@ public function setThread($thread);
    */
   public function permalink();
 
+  /**
+   * Get the comment type id for this comment.
+   *
+   * @return string
+   *   The id of the comment type.
+   */
+  public function getTypeId();
+
 }
diff --git a/core/modules/comment/src/CommentManager.php b/core/modules/comment/src/CommentManager.php
index 7bd9f0f6267797a3355c0ba95b61915b803198a2..2b639a23ea54f3828627715a9567ea5851722363 100644
--- a/core/modules/comment/src/CommentManager.php
+++ b/core/modules/comment/src/CommentManager.php
@@ -9,6 +9,7 @@
 
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
@@ -16,6 +17,8 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldInstanceConfig;
 
 /**
  * Comment manager contains common functions to manage comment fields.
@@ -103,9 +106,27 @@ public function getAllFields() {
   /**
    * {@inheritdoc}
    */
-  public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN) {
+  public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN, $comment_type_id = 'comment') {
+    $comment_type_storage = $this->entityManager->getStorage('comment_type');
+    if ($comment_type = $comment_type_storage->load($comment_type_id)) {
+      if ($comment_type->getTargetEntityTypeId() !== $entity_type) {
+        throw new \InvalidArgumentException(String::format('The given comment type id %id can only be used with the %entity_type entity type', array(
+          '%id' => $comment_type_id,
+          '%entity_type' => $entity_type,
+        )));
+      }
+    }
+    else {
+      // Silently create the comment-type for the calling code.
+      $comment_type_storage->create(array(
+        'id' => $comment_type_id,
+        'label' => Unicode::ucfirst($comment_type_id),
+        'target_entity_type_id' => $entity_type,
+        'description' => 'Default comment field',
+      ))->save();
+    }
     // Make sure the field doesn't already exist.
-    if (!$this->entityManager->getStorage('field_config')->load($entity_type . '.' . $field_name)) {
+    if (!FieldConfig::loadByName($entity_type, $field_name)) {
       // Add a default comment field for existing node comments.
       $field = $this->entityManager->getStorage('field_config')->create(array(
         'entity_type' => $entity_type,
@@ -113,14 +134,14 @@ public function addDefaultField($entity_type, $bundle, $field_name = 'comment',
         'type' => 'comment',
         'translatable' => '0',
         'settings' => array(
-          'description' => 'Default comment field',
+          'comment_type' => $comment_type_id,
         ),
       ));
       // Create the field.
       $field->save();
     }
     // Make sure the instance doesn't already exist.
-    if (!$this->entityManager->getStorage('field_instance_config')->load($entity_type . '.' . $bundle . '.' . $field_name)) {
+    if (!array_key_exists($field_name, $this->entityManager->getFieldDefinitions($entity_type, $bundle))) {
       $instance = $this->entityManager->getStorage('field_instance_config')->create(array(
         'label' => 'Comment settings',
         'description' => '',
@@ -164,7 +185,7 @@ public function addDefaultField($entity_type, $bundle, $field_name = 'comment',
           'weight' => 20,
         ))
         ->save();
-        // The comment field should be hidden in all other view displays.
+      // The comment field should be hidden in all other view displays.
       foreach ($this->entityManager->getViewModes($entity_type) as $id => $view_mode) {
         $display = entity_get_display($entity_type, $bundle, $id);
         // Only update existing displays.
@@ -174,15 +195,15 @@ public function addDefaultField($entity_type, $bundle, $field_name = 'comment',
       }
 
     }
-    $this->addBodyField($entity_type, $field_name);
+    $this->addBodyField($comment_type_id);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function addBodyField($entity_type, $field_name) {
+  public function addBodyField($comment_type_id) {
     // Create the field if needed.
-    $field = $this->entityManager->getStorage('field_config')->load('comment.comment_body');
+    $field = FieldConfig::loadByName('comment', 'comment_body');
     if (!$field) {
       $field = $this->entityManager->getStorage('field_config')->create(array(
         'name' => 'comment_body',
@@ -191,32 +212,27 @@ public function addBodyField($entity_type, $field_name) {
       ));
       $field->save();
     }
-    // Create the instance if needed, field name defaults to 'comment'.
-    $comment_bundle = $entity_type . '__' . $field_name;
-    $field_instance = $this->entityManager
-      ->getStorage('field_instance_config')
-      ->load("comment.$comment_bundle.comment_body");
-    if (!$field_instance) {
+    if (!FieldInstanceConfig::loadByName('comment', $comment_type_id, 'comment_body')) {
       // Attaches the body field by default.
       $field_instance = $this->entityManager->getStorage('field_instance_config')->create(array(
         'field_name' => 'comment_body',
         'label' => 'Comment',
         'entity_type' => 'comment',
-        'bundle' => $comment_bundle,
+        'bundle' => $comment_type_id,
         'settings' => array('text_processing' => 1),
         'required' => TRUE,
       ));
       $field_instance->save();
 
       // Assign widget settings for the 'default' form mode.
-      entity_get_form_display('comment', $comment_bundle, 'default')
+      entity_get_form_display('comment', $comment_type_id, 'default')
         ->setComponent('comment_body', array(
           'type' => 'text_textarea',
         ))
         ->save();
 
       // Assign display settings for the 'default' view mode.
-      entity_get_display('comment', $comment_bundle, 'default')
+      entity_get_display('comment', $comment_type_id, 'default')
         ->setComponent('comment_body', array(
           'label' => 'hidden',
           'type' => 'text_default',
@@ -226,16 +242,6 @@ public function addBodyField($entity_type, $field_name) {
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getFieldUIPageTitle($commented_entity_type, $field_name) {
-    $field_info = $this->getFields($commented_entity_type);
-    $sample_bundle = reset($field_info[$field_name]['bundles']);
-    $sample_definition = $this->entityManager->getFieldDefinitions($commented_entity_type, $sample_bundle)[$field_name];
-    return String::checkPlain($sample_definition->getLabel());
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/comment/src/CommentManagerInterface.php b/core/modules/comment/src/CommentManagerInterface.php
index f302e186fd4826278cf81822066415600ac08761..879706574aa6c108562376af71ef593e1f8109c9 100644
--- a/core/modules/comment/src/CommentManagerInterface.php
+++ b/core/modules/comment/src/CommentManagerInterface.php
@@ -48,36 +48,24 @@ public function getAllFields();
    * @param string $bundle
    *   The bundle to attach the default comment field instance to.
    * @param string $field_name
-   *   (optional) Field name to use for the comment field. Defaults to 'comment'.
+   *   (optional) Field name to use for the comment field. Defaults to
+   *     'comment'.
    * @param int $default_value
    *   (optional) Default value, one of CommentItemInterface::HIDDEN,
    *   CommentItemInterface::OPEN, CommentItemInterface::CLOSED. Defaults to
    *   CommentItemInterface::OPEN.
+   * @param string $comment_type_id
+   *   (optional) ID of comment type to use. Defaults to 'comment'.
    */
-  public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN);
+  public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN, $comment_type_id = 'comment');
 
   /**
    * Creates a comment_body field instance.
    *
-   * @param string $entity_type
-   *   The type of the entity to which the comment field attached.
-   * @param string $field_name
-   *   Name of the comment field to add comment_body field.
-   */
-  public function addBodyField($entity_type, $field_name);
-
-  /**
-   * Builds human readable page title for field_ui management screens.
-   *
-   * @param string $commented_entity_type
-   *   The entity type to which the comment field is attached.
-   * @param string $field_name
-   *   The comment field for which the overview is to be displayed.
-   *
-   * @return string
-   *   The human readable field name.
+   * @param string $comment_type
+   *   The comment bundle.
    */
-  public function getFieldUIPageTitle($commented_entity_type, $field_name);
+  public function addBodyField($comment_type);
 
   /**
    * Provides a message if posting comments is forbidden.
diff --git a/core/modules/comment/src/CommentStatistics.php b/core/modules/comment/src/CommentStatistics.php
index 9e3fbd10e3988e290fcbcabb29b51c7bf52b8f39..fbbdff42463348896adc60d625a67642a736e1e0 100644
--- a/core/modules/comment/src/CommentStatistics.php
+++ b/core/modules/comment/src/CommentStatistics.php
@@ -95,7 +95,7 @@ public function create(ContentEntityInterface $entity, $fields) {
       ->fields(array(
         'entity_id',
         'entity_type',
-        'field_id',
+        'field_name',
         'cid',
         'last_comment_timestamp',
         'last_comment_name',
@@ -126,7 +126,7 @@ public function create(ContentEntityInterface $entity, $fields) {
       $query->values(array(
         'entity_id' => $entity->id(),
         'entity_type' => $entity->getEntityTypeId(),
-        'field_id' => $entity->getEntityTypeId() . '__' . $field_name,
+        'field_name' => $field_name,
         'cid' => 0,
         'last_comment_timestamp' => $last_comment_timestamp,
         'last_comment_name' => NULL,
@@ -157,7 +157,7 @@ public function getRankingInfo() {
           'alias' => 'ces',
           // Default to comment field as this is the most common use case for
           // nodes.
-          'on' => "ces.entity_id = i.sid AND ces.entity_type = 'node' AND ces.field_id = 'node__comment'",
+          'on' => "ces.entity_id = i.sid AND ces.entity_type = 'node' AND ces.field_name = 'comment'",
         ),
         // Inverse law that maps the highest reply count on the site to 1 and 0
         // to 0. Note that the CAST here is necessary for PostgreSQL, because the
@@ -183,7 +183,7 @@ public function update(CommentInterface $comment) {
     $query->addExpression('COUNT(cid)');
     $count = $query->condition('c.entity_id', $comment->getCommentedEntityId())
       ->condition('c.entity_type', $comment->getCommentedEntityTypeId())
-      ->condition('c.field_id', $comment->getFieldId())
+      ->condition('c.field_name', $comment->getFieldName())
       ->condition('c.status', CommentInterface::PUBLISHED)
       ->execute()
       ->fetchField();
@@ -194,7 +194,7 @@ public function update(CommentInterface $comment) {
         ->fields('c', array('cid', 'name', 'changed', 'uid'))
         ->condition('c.entity_id', $comment->getCommentedEntityId())
         ->condition('c.entity_type', $comment->getCommentedEntityTypeId())
-        ->condition('c.field_id', $comment->getFieldId())
+        ->condition('c.field_name', $comment->getFieldName())
         ->condition('c.status', CommentInterface::PUBLISHED)
         ->orderBy('c.created', 'DESC')
         ->range(0, 1)
@@ -212,7 +212,7 @@ public function update(CommentInterface $comment) {
         ->keys(array(
           'entity_id' => $comment->getCommentedEntityId(),
           'entity_type' => $comment->getCommentedEntityTypeId(),
-          'field_id' => $comment->getFieldId(),
+          'field_name' => $comment->getFieldName(),
         ))
         ->execute();
     }
@@ -241,7 +241,7 @@ public function update(CommentInterface $comment) {
         ))
         ->condition('entity_id', $comment->getCommentedEntityId())
         ->condition('entity_type', $comment->getCommentedEntityTypeId())
-        ->condition('field_id', $comment->getFieldId())
+        ->condition('field_name', $comment->getFieldName())
         ->execute();
     }
   }
diff --git a/core/modules/comment/src/CommentStorage.php b/core/modules/comment/src/CommentStorage.php
index 5526d2be0640d0011629343558c8aba463a2f408..2cffb5e3dd7787dd29c034fbd515936b392fe0ae 100644
--- a/core/modules/comment/src/CommentStorage.php
+++ b/core/modules/comment/src/CommentStorage.php
@@ -95,7 +95,7 @@ public function updateEntityStatistics(CommentInterface $comment) {
   public function getMaxThread(EntityInterface $comment) {
     $query = $this->database->select('comment', 'c')
       ->condition('entity_id', $comment->getCommentedEntityId())
-      ->condition('field_id', $comment->getFieldId())
+      ->condition('field_name', $comment->getFieldName())
       ->condition('entity_type', $comment->getCommentedEntityTypeId());
     $query->addExpression('MAX(thread)', 'thread');
     return $query->execute()
@@ -108,7 +108,7 @@ public function getMaxThread(EntityInterface $comment) {
   public function getMaxThreadPerThread(EntityInterface $comment) {
     $query = $this->database->select('comment', 'c')
       ->condition('entity_id', $comment->getCommentedEntityId())
-      ->condition('field_id', $comment->getFieldId())
+      ->condition('field_name', $comment->getFieldName())
       ->condition('entity_type', $comment->getCommentedEntityTypeId())
       ->condition('thread', $comment->getParentComment()->getThread() . '.%', 'LIKE');
     $query->addExpression('MAX(thread)', 'thread');
@@ -138,7 +138,6 @@ public function getSchema() {
     $schema['comment']['fields']['pid']['not null'] = TRUE;
     $schema['comment']['fields']['status']['not null'] = TRUE;
     $schema['comment']['fields']['entity_id']['not null'] = TRUE;
-    $schema['comment']['fields']['field_id']['not null'] = TRUE;
     $schema['comment']['fields']['created']['not null'] = TRUE;
     $schema['comment']['fields']['thread']['not null'] = TRUE;
 
@@ -149,7 +148,7 @@ public function getSchema() {
       'comment__num_new' => array(
         'entity_id',
         array('entity_type', 32),
-        array('field_id', 32),
+        'comment_type',
         'status',
         'created',
         'cid',
@@ -158,7 +157,7 @@ public function getSchema() {
       'comment__entity_langcode' => array(
         'entity_id',
         array('entity_type', 32),
-        array('field_id', 32),
+        'comment_type',
         'langcode',
       ),
       'comment__created' => array('created'),
diff --git a/core/modules/comment/src/CommentTypeForm.php b/core/modules/comment/src/CommentTypeForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..2454a875c7051280c01e5b1442426d4a1882e6bc
--- /dev/null
+++ b/core/modules/comment/src/CommentTypeForm.php
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\CommentTypeForm.
+ */
+
+namespace Drupal\comment;
+
+use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Logger\LoggerChannelInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Base form controller for category edit forms.
+ */
+class CommentTypeForm extends EntityForm {
+
+  /**
+   * Entity manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * Logger Channel service.
+   *
+   * @var \Drupal\Core\Logger\LoggerChannelInterface
+   */
+  protected $logger;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity.manager'),
+      $container->get('logger.factory')->get('comment')
+    );
+  }
+
+  /**
+   * Constructs a CommentTypeFormController
+   *
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager service.
+   * @param \Drupal\Core\Logger\LoggerChannelInterface
+   *   The logger channel.
+   */
+  function __construct(EntityManagerInterface $entity_manager, LoggerChannelInterface $logger) {
+    $this->entityManager = $entity_manager;
+    $this->logger = $logger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, array &$form_state) {
+    $form = parent::form($form, $form_state);
+
+    $comment_type = $this->entity;
+
+    $form['label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Label'),
+      '#maxlength' => 255,
+      '#default_value' => $comment_type->label(),
+      '#required' => TRUE,
+    );
+    $form['id'] = array(
+      '#type' => 'machine_name',
+      '#default_value' => $comment_type->id(),
+      '#machine_name' => array(
+        'exists' => '\Drupal\comment\Entity\CommentType::load',
+      ),
+      '#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
+      '#disabled' => !$comment_type->isNew(),
+    );
+
+    $form['description'] = array(
+      '#type' => 'textarea',
+      '#default_value' => $comment_type->description,
+      '#description' => t('Describe this comment type. The text will be displayed on the <em>Comment types</em> administration overview page'),
+      '#title' => t('Description'),
+    );
+
+    $options = array();
+    foreach ($this->entityManager->getDefinitions() as $entity_type) {
+      if ($entity_type->isFieldable()) {
+        $options[$entity_type->id()] = $entity_type->getLabel();
+      }
+    }
+    $form['target_entity_type_id'] = array(
+      '#type' => 'select',
+      '#default_value' => $comment_type->getTargetEntityTypeId(),
+      '#title' => t('Target entity type'),
+      '#options' => $options,
+    );
+
+    if ($this->moduleHandler->moduleExists('content_translation')) {
+      $form['language'] = array(
+        '#type' => 'details',
+        '#title' => t('Language settings'),
+        '#group' => 'additional_settings',
+      );
+
+      $language_configuration = language_get_default_configuration('comment', $comment_type->id());
+      $form['language']['language_configuration'] = array(
+        '#type' => 'language_configuration',
+        '#entity_information' => array(
+          'entity_type' => 'comment',
+          'bundle' => $comment_type->id(),
+        ),
+        '#default_value' => $language_configuration,
+      );
+
+      $form['#submit'][] = 'language_configuration_element_submit';
+    }
+
+    $form['actions'] = array('#type' => 'actions');
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, array &$form_state) {
+    $comment_type = $this->entity;
+    $status = $comment_type->save();
+
+    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+    if ($status == SAVED_UPDATED) {
+      drupal_set_message(t('Comment type %label has been updated.', array('%label' => $comment_type->label())));
+      $this->logger->notice('Comment type %label has been updated.', array('%label' => $comment_type->label(), 'link' => $edit_link));
+    }
+    else {
+      drupal_set_message(t('Comment type %label has been added.', array('%label' => $comment_type->label())));
+      $this->logger->notice('Comment type %label has been added.', array('%label' => $comment_type->label(), 'link' =>  $edit_link));
+    }
+
+    $form_state['redirect_route']['route_name'] = 'comment.type_list';
+  }
+
+}
diff --git a/core/modules/comment/src/CommentTypeInterface.php b/core/modules/comment/src/CommentTypeInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ccc0c163c0e082fd56115f70d324930478af836
--- /dev/null
+++ b/core/modules/comment/src/CommentTypeInterface.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Entity\CommentTypeInterface.
+ */
+
+namespace Drupal\comment;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface defining a comment type entity.
+ */
+interface CommentTypeInterface extends ConfigEntityInterface {
+
+  /**
+   * Returns the comment type description.
+   *
+   * @return string
+   *   The comment-type description.
+   */
+  public function getDescription();
+
+  /**
+   * Sets the description of the comment type.
+   *
+   * @param string $description
+   *   The new description.
+   *
+   * @return $this
+   */
+  public function setDescription($description);
+
+  /**
+   * Gets the target entity type id for this comment type.
+   *
+   * @return string
+   *   The target entity type id.
+   */
+  public function getTargetEntityTypeId();
+
+}
diff --git a/core/modules/comment/src/CommentTypeListBuilder.php b/core/modules/comment/src/CommentTypeListBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..7f54ce935c3176c134fe3e1028d6f7ab015607b2
--- /dev/null
+++ b/core/modules/comment/src/CommentTypeListBuilder.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\CommentTypeListBuilder.
+ */
+
+namespace Drupal\comment;
+
+use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Xss;
+use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a class to build a listing of comment type entities.
+ *
+ * @see \Drupal\comment\Entity\CommentType
+ */
+class CommentTypeListBuilder extends ConfigEntityListBuilder {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    // Place the edit operation after the operations added by field_ui.module
+    // which have the weights 15, 20, 25.
+    if (isset($operations['edit'])) {
+      $operations['edit']['weight'] = 30;
+    }
+    return $operations;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader() {
+    $header['type'] = t('Comment type');
+    $header['description'] = t('Description');
+    return $header + parent::buildHeader();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $entity) {
+    $row['type'] = String::checkPlain($entity->label());
+    $row['description'] = Xss::filterAdmin($entity->getDescription());
+    return $row + parent::buildRow($entity);
+  }
+
+}
diff --git a/core/modules/comment/src/CommentViewBuilder.php b/core/modules/comment/src/CommentViewBuilder.php
index 5b6853099c4c13ae3176afc2a480281b25d043dc..b7cba52325cb44e42e9879e963eff1fcb223e9de 100644
--- a/core/modules/comment/src/CommentViewBuilder.php
+++ b/core/modules/comment/src/CommentViewBuilder.php
@@ -110,7 +110,7 @@ public function buildComponents(array &$build, array $entities, array $displays,
         throw new \InvalidArgumentException(t('Invalid entity for comment.'));
       }
       $build[$id]['#entity'] = $entity;
-      $build[$id]['#theme'] = 'comment__' . $entity->getFieldId() . '__' . $commented_entity->bundle();
+      $build[$id]['#theme'] = 'comment__' . $entity->getFieldName() . '__' . $commented_entity->bundle();
       $callback = '\Drupal\comment\CommentViewBuilder::renderLinks';
       $context = array(
         'comment_entity_id' => $entity->id(),
diff --git a/core/modules/comment/src/Controller/AdminController.php b/core/modules/comment/src/Controller/AdminController.php
index 9c8d43c88ffd65da9fc7a86699ff3416b6ab6e79..4c1592f1e2c57688aeadcfa7c3b3e1c6da1a0dbd 100644
--- a/core/modules/comment/src/Controller/AdminController.php
+++ b/core/modules/comment/src/Controller/AdminController.php
@@ -7,12 +7,8 @@
 
 namespace Drupal\comment\Controller;
 
-use Drupal\comment\CommentManagerInterface;
-use Drupal\field\FieldConfigInterface;
-use Drupal\Component\Utility\String;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Form\FormBuilderInterface;
-use Drupal\field_ui\FieldUI;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -21,13 +17,6 @@
  */
 class AdminController extends ControllerBase {
 
-  /**
-   * The comment manager service.
-   *
-   * @var \Drupal\comment\CommentManagerInterface
-   */
-  protected $commentManager;
-
   /**
    * The form builder.
    *
@@ -40,7 +29,6 @@ class AdminController extends ControllerBase {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('comment.manager'),
       $container->get('form_builder')
     );
   }
@@ -48,136 +36,13 @@ public static function create(ContainerInterface $container) {
   /**
    * Constructs an AdminController object.
    *
-   * @param \Drupal\comment\CommentManagerInterface $comment_manager
-   *   The comment manager service.
    * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
    *   The form builder.
    */
-  public function __construct(CommentManagerInterface $comment_manager, FormBuilderInterface $form_builder) {
-    $this->commentManager = $comment_manager;
+  public function __construct(FormBuilderInterface $form_builder) {
     $this->formBuilder = $form_builder;
   }
 
-  /**
-   * Returns an overview of comment fields in use on the site.
-   *
-   * @return array
-   *   A renderable array containing a list of comment fields, the entity
-   *   type and bundle combinations on which they are in use and various
-   *   operation links for configuring each field.
-   */
-  public function overviewBundles() {
-    $header = array(
-      'field_name' => $this->t('Field name'),
-      'description' => array(
-        'data' => $this->t('Description'),
-        'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
-      ),
-      'usage' => array(
-        'data' => $this->t('Used in'),
-        'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
-      ),
-      'type' => $this->t('Type'),
-    );
-
-    // Add a column for field UI operations if the Field UI module is enabled.
-    $field_ui_enabled = $this->moduleHandler()->moduleExists('field_ui');
-    if ($field_ui_enabled) {
-      $header['operations'] = $this->t('Operations');
-    }
-
-    $entity_bundles = $this->entityManager()->getAllBundleInfo();
-    $entity_types = $this->entityManager()->getDefinitions();
-    $rows = array();
-
-    // Fetch a list of all comment fields.
-    $fields = $this->commentManager->getAllFields();
-
-    foreach ($fields as $entity_type => $data) {
-      $field_storage_definitions = $this->entityManager()->getFieldStorageDefinitions($entity_type);
-      foreach ($data as $field_name => $field_info_map) {
-        $storage_definition = $field_storage_definitions[$field_name];
-        // Initialize the row.
-        $row = array(
-          'class' => $storage_definition->get('locked') ? array('field-disabled') : array(''),
-        );
-
-        $label = $storage_definition->getLabel();
-        if ($storage_definition instanceof FieldConfigInterface) {
-          $bundles = $storage_definition->getBundles();
-          $sample_bundle = reset($bundles);
-          $field_definitions = $this->entityManager()->getFieldDefinitions($entity_type, $sample_bundle);
-          $label = $field_definitions[$field_name]->getLabel();
-        }
-
-        $tokens = array(
-          '@label' => $label,
-          '@field_name' => $field_name,
-        );
-        $row['data']['field_name']['data'] = $storage_definition->get('locked') ? $this->t('@label (@field_name) (Locked)', $tokens) : $this->t('@label (@field_name)', $tokens);
-
-        $row['data']['description']['data'] = $storage_definition->getSetting('description');
-        $row['data']['usage']['data'] = array(
-          '#theme' => 'item_list',
-          '#items' => array(),
-        );
-        foreach ($field_info_map['bundles'] as $bundle) {
-          if (isset($entity_bundles[$entity_type][$bundle])) {
-            // Add the current instance.
-            if ($field_ui_enabled && $route_info = FieldUI::getOverviewRouteInfo($entity_type, $bundle)) {
-              $row['data']['usage']['data']['#items'][] = \Drupal::linkGenerator()->generateFromUrl($entity_bundles[$entity_type][$bundle]['label'], $route_info);
-            }
-            else {
-              $row['data']['usage']['data']['#items'][] = $entity_bundles[$entity_type][$bundle]['label'];
-            }
-          }
-        }
-
-        $row['data']['type']['data'] = String::checkPlain($entity_types[$entity_type]->getLabel());
-
-        if ($field_ui_enabled) {
-          if ($this->currentUser()->hasPermission('administer comment fields')) {
-            $links['fields'] = array(
-              'title' => $this->t('Manage fields'),
-              'href' => 'admin/structure/comments/manage/' . $entity_type . '__' . $field_name . '/fields',
-              'weight' => 5,
-            );
-          }
-          if ($this->currentUser()->hasPermission('administer comment display')) {
-            $links['display'] = array(
-              'title' => $this->t('Manage display'),
-              'href' => 'admin/structure/comments/manage/' . $entity_type . '__' . $field_name . '/display',
-              'weight' => 10,
-            );
-          }
-          if ($this->currentUser()->hasPermission('administer comment form display')) {
-            $links['form_display'] = array(
-              'title' => $this->t('Manage form display'),
-              'href' => 'admin/structure/comments/manage/' . $entity_type . '__' . $field_name . '/form-display',
-              'weight' => 10,
-            );
-          }
-
-          $row['data']['operations']['data'] = array(
-            '#type' => 'operations',
-            '#links' => $links,
-          );
-        }
-        $rows[$entity_type . '__' . $field_name] = $row;
-      }
-    }
-
-    $build['overview'] = array(
-      '#type' => 'table',
-      '#header' => $header,
-      '#rows' => $rows,
-      '#empty' => $this->t('No comment forms available.'),
-    );
-    $build['#title'] = $this->t('Comment forms');
-
-    return $build;
-  }
-
   /**
    * Presents an administrative comment listing.
    *
diff --git a/core/modules/comment/src/Controller/CommentController.php b/core/modules/comment/src/Controller/CommentController.php
index 1e73008cc9a2f2486e8c97334abba471a91f7285..94fb25efffb96b9be8073bb1ff62d379444f4c33 100644
--- a/core/modules/comment/src/Controller/CommentController.php
+++ b/core/modules/comment/src/Controller/CommentController.php
@@ -255,7 +255,7 @@ public function getReplyForm(Request $request, $entity_type, $entity_id, $field_
       'entity_id' => $entity->id(),
       'pid' => $pid,
       'entity_type' => $entity->getEntityTypeId(),
-      'field_id' => $entity->getEntityTypeId() . '__' . $field_name,
+      'field_name' => $field_name,
     ));
     $build['comment_form'] = $this->entityFormBuilder()->getForm($comment);
 
diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php
index 8afc5b3415846290e0e77805f05c3f00218c7185..d7c7d11c4e1a39f5d7c228803123a2b571ac34d2 100644
--- a/core/modules/comment/src/Entity/Comment.php
+++ b/core/modules/comment/src/Entity/Comment.php
@@ -13,7 +13,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\FieldDefinition;
-use Drupal\Core\TypedData\DataDefinition;
+use Drupal\field\Entity\FieldConfig;
 use Drupal\user\UserInterface;
 
 /**
@@ -39,7 +39,7 @@
  *   translatable = TRUE,
  *   entity_keys = {
  *     "id" = "cid",
- *     "bundle" = "field_id",
+ *     "bundle" = "comment_type",
  *     "label" = "subject",
  *     "uuid" = "uuid"
  *   },
@@ -47,8 +47,9 @@
  *     "canonical" = "comment.permalink",
  *     "delete-form" = "comment.confirm_delete",
  *     "edit-form" = "comment.edit_page",
- *     "admin-form" = "comment.bundle"
- *   }
+ *     "admin-form" = "comment.type_edit"
+ *   },
+ *   bundle_entity_type = "comment_type"
  * )
  */
 class Comment extends ContentEntityBase implements CommentInterface {
@@ -284,20 +285,15 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setLabel(t('Entity type'))
       ->setDescription(t('The entity type to which this comment is attached.'));
 
-    // @todo Convert to the entity_reference field in
-    // https://drupal.org/node/2149859.
-    $fields['field_id'] = FieldDefinition::create('string')
-      ->setLabel(t('Field ID'))
-      ->setDescription(t('The comment field id.'));
+    $fields['comment_type'] = FieldDefinition::create('entity_reference')
+      ->setLabel(t('Comment Type'))
+      ->setDescription(t('The comment type.'))
+      ->setSetting('target_type', 'comment_type');
 
     $fields['field_name'] = FieldDefinition::create('string')
       ->setLabel(t('Comment field name'))
       ->setDescription(t('The field name through which this comment was added.'))
-      ->setComputed(TRUE);
-
-    $item_definition = $fields['field_name']->getItemDefinition();
-    $item_definition->setClass('\Drupal\comment\CommentFieldNameItem');
-    $fields['field_name']->setItemDefinition($item_definition);
+      ->setSetting('max_length', 32);
 
     return $fields;
   }
@@ -306,10 +302,12 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    * {@inheritdoc}
    */
   public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
-    list($target_type) = explode('__', $bundle, 2);
-    $fields['entity_id'] = clone $base_field_definitions['entity_id'];
-    $fields['entity_id']->setSetting('target_type', $target_type);
-    return $fields;
+    if ($comment_type = CommentType::load($bundle)) {
+      $fields['entity_id'] = clone $base_field_definitions['entity_id'];
+      $fields['entity_id']->setSetting('target_type', $comment_type->getTargetEntityTypeId());
+      return $fields;
+    }
+    return array();
   }
 
   /**
@@ -351,15 +349,8 @@ public function getCommentedEntityTypeId() {
   /**
    * {@inheritdoc}
    */
-  public function getFieldId() {
-    return $this->get('field_id')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setFieldId($field_id) {
-    $this->set('field_id', $field_id);
+  public function setFieldName($field_name) {
+    $this->set('field_name', $field_name);
     return $this;
   }
 
@@ -505,8 +496,9 @@ public function getChangedTime() {
    * {@inheritdoc}
    */
   public static function preCreate(EntityStorageInterface $storage, array &$values) {
-    if (empty($values['field_id']) && !empty($values['field_name']) && !empty($values['entity_type'])) {
-      $values['field_id'] = $values['entity_type'] . '__' . $values['field_name'];
+    if (empty($values['comment_type']) && !empty($values['field_name']) && !empty($values['entity_type'])) {
+      $field = FieldConfig::loadByName($values['entity_type'], $values['field_name']);
+      $values['comment_type'] = $field->getSetting('comment_type');
     }
   }
 
@@ -540,4 +532,14 @@ public function setOwner(UserInterface $account) {
     return $this;
   }
 
+  /**
+   * Get the comment type ID for this comment.
+   *
+   * @return string
+   *   The ID of the comment type.
+   */
+  public function getTypeId() {
+    return $this->bundle();
+  }
+
 }
diff --git a/core/modules/comment/src/Entity/CommentType.php b/core/modules/comment/src/Entity/CommentType.php
new file mode 100644
index 0000000000000000000000000000000000000000..4d7dd1df4e604e2311bec0bcdc41476d9411b36a
--- /dev/null
+++ b/core/modules/comment/src/Entity/CommentType.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Entity\CommentType.
+ */
+
+namespace Drupal\comment\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\comment\CommentTypeInterface;
+
+/**
+ * Defines the comment type entity.
+ *
+ * @ConfigEntityType(
+ *   id = "comment_type",
+ *   label = @Translation("Comment type"),
+ *   controllers = {
+ *     "form" = {
+ *       "default" = "Drupal\comment\CommentTypeForm",
+ *       "add" = "Drupal\comment\CommentTypeForm",
+ *       "edit" = "Drupal\comment\CommentTypeForm",
+ *       "delete" = "Drupal\comment\Form\CommentTypeDeleteForm"
+ *     },
+ *     "list_builder" = "Drupal\comment\CommentTypeListBuilder"
+ *   },
+ *   admin_permission = "administer comment types",
+ *   config_prefix = "type",
+ *   bundle_of = "comment",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label"
+ *   },
+ *   links = {
+ *     "delete-form" = "comment.type_delete",
+ *     "edit-form" = "comment.type_edit",
+ *     "add-form" = "comment.type_add"
+ *   }
+ * )
+ */
+class CommentType extends ConfigEntityBundleBase implements CommentTypeInterface {
+
+  /**
+   * The comment type ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The comment type label.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * The description of the comment type.
+   *
+   * @var string
+   */
+  public $description;
+
+  /**
+   * The target entity type.
+   *
+   * @var string
+   */
+  public $target_entity_type_id;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->description;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setDescription($description) {
+    $this->description = $description;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTargetEntityTypeId() {
+    return $this->target_entity_type_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
+    parent::postSave($storage, $update);
+    if (!$update && !$this->isSyncing()) {
+      \Drupal::service('comment.manager')->addBodyField($this->id());
+    }
+  }
+
+}
diff --git a/core/modules/comment/src/Form/CommentTypeDeleteForm.php b/core/modules/comment/src/Form/CommentTypeDeleteForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c32d2f9f6363d51de350fd5bb46e84082b5aa6f
--- /dev/null
+++ b/core/modules/comment/src/Form/CommentTypeDeleteForm.php
@@ -0,0 +1,150 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Form\CommentTypeDeleteForm.
+ */
+
+namespace Drupal\comment\Form;
+
+use Drupal\comment\CommentManagerInterface;
+use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Logger\LoggerChannelInterface;
+use Drupal\Core\Url;
+use Drupal\field\Entity\FieldConfig;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a confirmation form for deleting a comment type entity.
+ */
+class CommentTypeDeleteForm extends EntityConfirmFormBase {
+
+  /**
+   * The query factory to create entity queries.
+   *
+   * @var \Drupal\Core\Entity\Query\QueryFactory
+   */
+  public $queryFactory;
+
+  /**
+   * The comment manager service.
+   *
+   * @var \Drupal\comment\CommentManagerInterface
+   */
+  protected $commentManager;
+
+  /**
+   * The entity manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * The comment channel logger.
+   *
+   * @var \Drupal\Core\Logger\LoggerChannelInterface
+   */
+  protected $logger;
+
+  /**
+   * The entity being used by this form.
+   *
+   * @var \Drupal\comment\CommentTypeInterface
+   */
+  protected $entity;
+
+  /**
+   * Constructs a query factory object.
+   *
+   * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
+   *   The entity query object.
+   * @param \Drupal\comment\CommentManagerInterface $comment_manager
+   *   The comment manager service.
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager service.
+   * @param \Drupal\Core\Logger\LoggerChannelInterface $logger
+   *   The logger channel.
+   */
+  public function __construct(QueryFactory $query_factory, CommentManagerInterface $comment_manager, EntityManager $entity_manager, LoggerChannelInterface $logger) {
+    $this->queryFactory = $query_factory;
+    $this->commentManager = $comment_manager;
+    $this->entityManager = $entity_manager;
+    $this->logger = $logger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity.query'),
+      $container->get('comment.manager'),
+      $container->get('entity.manager'),
+      $container->get('logger.factory')->get('comment')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return $this->t('Are you sure you want to delete %label?', array('%label' => $this->entity->label()));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelRoute() {
+    return new Url('comment.type_list');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return $this->t('Delete');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $comments = $this->queryFactory->get('comment')->condition('comment_type', $this->entity->id())->execute();
+    $entity_type = $this->entity->getTargetEntityTypeId();
+    $caption = '';
+    foreach (array_keys($this->commentManager->getFields($entity_type)) as $field_name) {
+      /** @var \Drupal\field\FieldConfigInterface $field */
+      if (($field = FieldConfig::loadByName($entity_type, $field_name)) && $field->getSetting('comment_type') == $this->entity->id() && !$field->deleted) {
+        $caption .= '<p>' . $this->t('%label is used by the %field field on your site. You can not remove this comment type until you have removed the field.', array(
+          '%label' => $this->entity->label(),
+          '%field' => $field->label(),
+        )) . '</p>';
+      }
+    }
+
+    if (!empty($comments)) {
+      $caption .= '<p>' . $this->formatPlural(count($comments), '%label is used by 1 comment on your site. You can not remove this comment type until you have removed all of the %label comments.', '%label is used by @count comments on your site. You may not remove %label until you have removed all of the %label comments.', array('%label' => $this->entity->label())) . '</p>';
+    }
+    if ($caption) {
+      $form['description'] = array('#markup' => $caption);
+      return $form;
+    }
+    else {
+      return parent::buildForm($form, $form_state);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submit(array $form, array &$form_state) {
+    $this->entity->delete();
+    $form_state['redirect_route']['route_name'] = 'comment.type_list';
+    drupal_set_message($this->t('Comment type %label has been deleted.', array('%label' => $this->entity->label())));
+    $this->logger->notice('comment type %label has been deleted.', array('%label' => $this->entity->label()));
+  }
+
+}
diff --git a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
index 50799b80fd3f28756c24d40e517c0a7ff6ba2bf1..7fb70aa39b7000fd204bf44e170818a46be41bce 100644
--- a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
+++ b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\Field\FieldType;
 
+use Drupal\comment\Entity\CommentType;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\Field\FieldItemBase;
@@ -30,7 +31,7 @@ class CommentItem extends FieldItemBase implements CommentItemInterface {
    */
   public static function defaultSettings() {
     return array(
-      'description' => '',
+      'comment_type' => '',
     ) + parent::defaultSettings();
   }
 
@@ -102,16 +103,12 @@ public function instanceSettingsForm(array $form, array &$form_state) {
 
     $settings = $this->getSettings();
 
-    $entity_type = $this->getEntity()->getEntityTypeId();
-    $field_name = $this->getFieldDefinition()->getName();
     $anonymous_user = new AnonymousUserSession();
 
     $element['comment'] = array(
       '#type' => 'details',
       '#title' => t('Comment form settings'),
       '#open' => TRUE,
-      '#bundle' => "{$entity_type}__{$field_name}",
-      '#process' => array(array(get_class($this), 'processSettingsElement')),
       '#attributes' => array(
         'class' => array('comment-instance-settings-form'),
       ),
@@ -193,40 +190,29 @@ public function isEmpty() {
     return FALSE;
   }
 
-  /**
-   * Process callback to add submit handler for instance settings form.
-   *
-   * Attaches the required translation entity handlers for the instance which
-   * correlates one to one with the comment bundle.
-   */
-  public static function processSettingsElement($element) {
-    // Settings should not be stored as nested.
-    $parents = $element['#parents'];
-    array_pop($parents);
-    $element['#parents'] = $parents;
-    // Add translation entity handlers.
-    if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
-      $comment_form = $element;
-      $comment_form_state['content_translation']['key'] = 'language_configuration';
-      $element += content_translation_enable_widget('comment', $element['#bundle'], $comment_form, $comment_form_state);
-      $element['content_translation']['#parents'] = $element['content_translation']['#array_parents'] = array(
-        'content_translation'
-      );
-    }
-    return $element;
-  }
-
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $element = array();
 
-    $element['description'] = array(
-      '#type' => 'textarea',
-      '#title' => t('Field description'),
-      '#description' => t('Describe this comment field. The text will be displayed on the <em>Comments Forms</em> page.'),
-      '#default_value' => $this->getSetting('description'),
+    // @todo Inject entity storage once typed-data supports container injection.
+    // See https://drupal.org/node/2053415 for more details.
+    $comment_types = CommentType::loadMultiple();
+    $options = array();
+    $entity_type = $this->getEntity()->getEntityTypeId();
+    foreach ($comment_types as $comment_type) {
+      if ($comment_type->getTargetEntityTypeId() == $entity_type) {
+        $options[$comment_type->id()] = $comment_type->label();
+      }
+    }
+    $element['comment_type'] = array(
+      '#type' => 'select',
+      '#title' => t('Comment type'),
+      '#options' => $options,
+      '#description' => t('Select the Comment type to use for this comment field.'),
+      '#default_value' => $this->getSetting('comment_type'),
+      '#disabled' => $has_data,
     );
     return $element;
   }
diff --git a/core/modules/comment/src/Routing/CommentBundleEnhancer.php b/core/modules/comment/src/Routing/CommentBundleEnhancer.php
deleted file mode 100644
index 783fcdaf4b256412777086f51384c7ec6f358005..0000000000000000000000000000000000000000
--- a/core/modules/comment/src/Routing/CommentBundleEnhancer.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\comment\Routing\CommentBundleEnhancer.
- */
-
-namespace Drupal\comment\Routing;
-
-use Drupal\Core\Entity\EntityManagerInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-
-/**
- * Constructs a route enhancer to extract values from comment bundles.
- *
- * Comment bundle names are of the form {entity_type}__{field_name}. This
- * enhancer extracts them from the path and makes them available as arguments
- * to controllers.
- */
-class CommentBundleEnhancer implements RouteEnhancerInterface {
-
-  /**
-   * The entity manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
-   */
-  protected $entityManager;
-
-  /**
-   * Constructs a CommentBundleEnhancer object.
-   *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager service.
-   */
-  public function __construct(EntityManagerInterface $entity_manager) {
-    $this->entityManager = $entity_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function enhance(array $defaults, Request $request) {
-    if (isset($defaults['bundle']) && ($bundles = $this->entityManager->getBundleInfo('comment')) && isset($bundles[$defaults['bundle']])) {
-      list($entity_type, $field_name) = explode('__', $defaults['bundle'], 2);
-      $defaults['commented_entity_type'] = $entity_type;
-      $defaults['field_name'] = $field_name;
-    }
-    return $defaults;
-  }
-
-}
diff --git a/core/modules/comment/src/Tests/CommentAdminTest.php b/core/modules/comment/src/Tests/CommentAdminTest.php
index 4f2f2112f1f13e1bde17b79a5d4947b175b8fae3..11d41137f54edf81a7fbe3eaacacf476c0040e91 100644
--- a/core/modules/comment/src/Tests/CommentAdminTest.php
+++ b/core/modules/comment/src/Tests/CommentAdminTest.php
@@ -157,11 +157,10 @@ public function testCommentAdmin() {
     // Login.
     $this->drupalLogin($this->admin_user);
     // Browse to comment bundle overview.
-    $this->drupalGet('admin/structure/comments');
+    $this->drupalGet('admin/structure/comment');
     $this->assertResponse(200);
     // Make sure titles visible.
-    $this->assertText('Field name');
-    $this->assertText('Used in');
+    $this->assertText('Comment type');
     $this->assertText('Description');
     // Make sure the description is present.
     $this->assertText('Default comment field');
diff --git a/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php b/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php
index ff8c05a58b9343e44285e0e100b3851cce696cdc..08fee4e06488bbdde090d1246c6455f5a614c5f3 100644
--- a/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php
+++ b/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php
@@ -57,25 +57,7 @@ public function setUp() {
 
     // Set up a field, so that the entity that'll be referenced bubbles up a
     // cache tag when rendering it entirely.
-    entity_create('field_config', array(
-      'name' => 'comment',
-      'entity_type' => 'entity_test',
-      'type' => 'comment',
-      'settings' => array(),
-    ))->save();
-    entity_create('field_instance_config', array(
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
-      'field_name' => 'comment',
-      'label' => 'Comment',
-      'settings' => array(),
-    ))->save();
-    entity_get_display('entity_test', 'entity_test', 'default')
-      ->setComponent('comment', array(
-        'type' => 'comment_default',
-        'settings' => array(),
-      ))
-      ->save();
+    \Drupal::service('comment.manager')->addDefaultField('entity_test', 'entity_test');
   }
 
   /**
@@ -110,6 +92,7 @@ public function testCacheTags() {
       'entity_id' => $commented_entity->id(),
       'entity_type' => 'entity_test',
       'field_name' => 'comment',
+      'comment_type' => 'comment',
       'status' => CommentInterface::PUBLISHED,
       'uid' => $user->id(),
     ));
diff --git a/core/modules/comment/src/Tests/CommentFieldsTest.php b/core/modules/comment/src/Tests/CommentFieldsTest.php
index d7657e1f0b8142947b5fe9d0f9cbb4cdf4921d5c..5dd3bb7f6b471be66db9e89c15f8580705f701bd 100644
--- a/core/modules/comment/src/Tests/CommentFieldsTest.php
+++ b/core/modules/comment/src/Tests/CommentFieldsTest.php
@@ -41,7 +41,7 @@ function testCommentDefaultFields() {
     $this->container->get('comment.manager')->addDefaultField('node', 'test_node_type');
 
     // Check that the 'comment_body' field is present on the comment bundle.
-    $instance = FieldInstanceConfig::loadByName('comment', 'node__comment', 'comment_body');
+    $instance = FieldInstanceConfig::loadByName('comment', 'comment', 'comment_body');
     $this->assertTrue(!empty($instance), 'The comment_body field is added when a comment bundle is created');
 
     $instance->delete();
@@ -59,11 +59,11 @@ function testCommentDefaultFields() {
     // new comment bundle.
     $field = FieldConfig::loadByName('comment', 'comment_body');
     $this->assertTrue($field, 'The comment_body field exists');
-    $instance = FieldInstanceConfig::loadByName('comment', 'node__comment', 'comment_body');
+    $instance = FieldInstanceConfig::loadByName('comment', 'comment', 'comment_body');
     $this->assertTrue(isset($instance), format_string('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
 
     // Test adding a field that defaults to CommentItemInterface::CLOSED.
-    $this->container->get('comment.manager')->addDefaultField('node', 'test_node_type', 'who_likes_ponies', CommentItemInterface::CLOSED);
+    $this->container->get('comment.manager')->addDefaultField('node', 'test_node_type', 'who_likes_ponies', CommentItemInterface::CLOSED, 'who_likes_ponies');
     $field = entity_load('field_instance_config', 'node.test_node_type.who_likes_ponies');
     $this->assertEqual($field->default_value[0]['status'], CommentItemInterface::CLOSED);
   }
@@ -130,10 +130,10 @@ function testCommentFormat() {
     // Disable text processing for comments.
     $this->drupalLogin($this->admin_user);
     $edit = array('instance[settings][text_processing]' => 0);
-    $this->drupalPostForm('admin/structure/comments/manage/node__comment/fields/comment.node__comment.comment_body', $edit, t('Save settings'));
+    $this->drupalPostForm('admin/structure/comment/manage/comment/fields/comment.comment.comment_body', $edit, t('Save settings'));
 
     // Change formatter settings.
-    $this->drupalGet('admin/structure/comments/manage/node__comment/display');
+    $this->drupalGet('admin/structure/comment/manage/comment/display');
     $edit = array('fields[comment_body][type]' => 'text_trimmed', 'refresh_rows' => 'comment_body');
     $commands = $this->drupalPostAjaxForm(NULL, $edit, array('op' => t('Refresh')));
     $this->assertTrue($commands, 'Ajax commands returned');
diff --git a/core/modules/comment/src/Tests/CommentLanguageTest.php b/core/modules/comment/src/Tests/CommentLanguageTest.php
index 260834fafb554713f53bce7e95c04d9cf19fb1aa..aa3d5aa34e537ca6367220af7d5fa02ffa20387f 100644
--- a/core/modules/comment/src/Tests/CommentLanguageTest.php
+++ b/core/modules/comment/src/Tests/CommentLanguageTest.php
@@ -121,7 +121,7 @@ function testCommentLanguage() {
           ->fields('c', array('cid'))
           ->condition('entity_id', $node->id())
           ->condition('entity_type', 'node')
-          ->condition('field_id', 'node__comment')
+          ->condition('field_name', 'comment')
           ->orderBy('cid', 'DESC')
           ->range(0, 1)
           ->execute()
diff --git a/core/modules/comment/src/Tests/CommentNonNodeTest.php b/core/modules/comment/src/Tests/CommentNonNodeTest.php
index 8f53832b2475b973bd85e68f8b17cc3ed6fca28c..b0a6156a2545c1da1de26a65d9bdfb5f3c017e8a 100644
--- a/core/modules/comment/src/Tests/CommentNonNodeTest.php
+++ b/core/modules/comment/src/Tests/CommentNonNodeTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\comment\Tests;
 
 use Drupal\comment\CommentInterface;
+use Drupal\comment\Entity\CommentType;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\field\Entity\FieldInstanceConfig;
 use Drupal\simpletest\WebTestBase;
@@ -40,12 +41,18 @@ function setUp() {
 
     // Create a bundle for entity_test.
     entity_test_create_bundle('entity_test', 'Entity Test', 'entity_test');
+    entity_create('comment_type', array(
+      'id' => 'comment',
+      'label' => 'Comment settings',
+      'description' => 'Comment settings',
+      'target_entity_type_id' => 'entity_test',
+    ))->save();
     // Create comment field on entity_test bundle.
     $this->container->get('comment.manager')->addDefaultField('entity_test', 'entity_test');
 
     // Verify that bundles are defined correctly.
     $bundles = \Drupal::entityManager()->getBundleInfo('comment');
-    $this->assertEqual($bundles['entity_test__comment']['label'], 'Comment settings');
+    $this->assertEqual($bundles['comment']['label'], 'Comment settings');
 
     // Create test user.
     $this->admin_user = $this->drupalCreateUser(array(
@@ -355,6 +362,15 @@ function testCommentFunctionality() {
     $this->assertFieldChecked('edit-default-value-input-comment-0-status-1');
     $this->assertNoFieldChecked('edit-default-value-input-comment-0-status-2');
 
+    // Add a new comment-type.
+    $bundle = CommentType::create(array(
+      'id' => 'foobar',
+      'label' => 'Foobar',
+      'description' => '',
+      'target_entity_type_id' => 'entity_test',
+    ));
+    $bundle->save();
+
     // Add a new comment field.
     $this->drupalGet('entity_test/structure/entity_test/fields');
     $edit = array(
@@ -363,10 +379,33 @@ function testCommentFunctionality() {
       'fields[_add_new_field][type]' => 'comment',
     );
     $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->drupalPostForm(NULL, array(), t('Save field settings'));
+    $this->drupalPostForm(NULL, array(
+      'field[settings][comment_type]' => 'foobar',
+    ), t('Save field settings'));
+
     $this->drupalPostForm(NULL, array(), t('Save settings'));
     $this->assertRaw(t('Saved %name configuration', array('%name' => 'Foobar')));
 
+    // Add a third comment field.
+    $this->drupalGet('entity_test/structure/entity_test/fields');
+    $edit = array(
+      'fields[_add_new_field][label]' => 'Barfoo',
+      'fields[_add_new_field][field_name]' => 'barfoo',
+      'fields[_add_new_field][type]' => 'comment',
+    );
+    $this->drupalPostForm(NULL, $edit, t('Save'));
+    // Re-use another comment type.
+    $this->drupalPostForm(NULL, array(
+      'field[settings][comment_type]' => 'foobar',
+    ), t('Save field settings'));
+    $this->drupalPostForm(NULL, array(), t('Save settings'));
+    $this->assertRaw(t('Saved %name configuration', array('%name' => 'Barfoo')));
+
+    // Check the field contains the correct comment type.
+    $field = entity_load('field_config', 'entity_test.field_barfoo');
+    $this->assertTrue($field);
+    $this->assertEqual($field->getSetting('comment_type'), 'foobar');
+
     // Test the new entity commenting inherits default.
     $random_label = $this->randomName();
     $data = array('bundle' => 'entity_test', 'name' => $random_label);
diff --git a/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php b/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php
index 014b3b1d58a6af09ba81a6138ea37420b9d0ae80..e1be25d978f1abc70a52c82c097930f6383e9ac7 100644
--- a/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php
+++ b/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
+use Drupal\comment\Entity\CommentType;
 use Drupal\simpletest\KernelTestBase;
 
 /**
@@ -19,7 +20,15 @@ class CommentStringIdEntitiesTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = array('comment', 'user', 'field', 'field_ui', 'entity_test');
+  public static $modules = array(
+    'comment',
+    'user',
+    'field',
+    'field_ui',
+    'entity',
+    'entity_test',
+    'text',
+  );
 
   public static function getInfo() {
     return array(
@@ -40,10 +49,19 @@ public function setUp() {
    */
   public function testCommentFieldNonStringId() {
     try {
+      $bundle = CommentType::create(array(
+        'id' => 'foo',
+        'label' => 'foo',
+        'description' => '',
+        'target_entity_type_id' => 'entity_test_string_id',
+      ));
+      $bundle->save();
       $field = entity_create('field_config', array(
         'name' => 'foo',
         'entity_type' => 'entity_test_string_id',
-        'settings' => array(),
+        'settings' => array(
+          'comment_type' => 'entity_test_string_id',
+        ),
         'type' => 'comment',
       ));
       $field->save();
diff --git a/core/modules/comment/src/Tests/CommentTestBase.php b/core/modules/comment/src/Tests/CommentTestBase.php
index 1931c9e3a3ebf4df769cc9682abbd3673415579d..a93110b3fcaae40d99c0a04a24fbb70aa76324cc 100644
--- a/core/modules/comment/src/Tests/CommentTestBase.php
+++ b/core/modules/comment/src/Tests/CommentTestBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Tests;
 
+use Drupal\comment\Entity\CommentType;
 use Drupal\comment\CommentInterface;
 use Drupal\field\Entity\FieldInstanceConfig;
 use Drupal\simpletest\WebTestBase;
@@ -58,6 +59,7 @@ function setUp() {
     $this->admin_user = $this->drupalCreateUser(array(
       'administer content types',
       'administer comments',
+      'administer comment types',
       'administer comment fields',
       'administer comment display',
       'skip comment approval',
@@ -353,4 +355,24 @@ function getUnapprovedComment($subject) {
     return $match[2];
   }
 
+  /**
+   * Creates a comment comment type (bundle).
+   *
+   * @param string $label
+   *   The comment type label.
+   *
+   * @return \Drupal\comment\Entity\CommentType
+   *   Created comment type.
+   */
+  protected function createCommentType($label) {
+    $bundle = CommentType::create(array(
+      'id' => $label,
+      'label' => $label,
+      'description' => '',
+      'target_entity_type_id' => 'node',
+    ));
+    $bundle->save();
+    return $bundle;
+  }
+
 }
diff --git a/core/modules/comment/src/Tests/CommentTranslationUITest.php b/core/modules/comment/src/Tests/CommentTranslationUITest.php
index 1749e1f6cc8baf0cdb2a85e9af4925d6d96b330a..7314c30d6ae2214a7e55797f6c5e20d6a770946a 100644
--- a/core/modules/comment/src/Tests/CommentTranslationUITest.php
+++ b/core/modules/comment/src/Tests/CommentTranslationUITest.php
@@ -39,7 +39,7 @@ public static function getInfo() {
   function setUp() {
     $this->entityTypeId = 'comment';
     $this->nodeBundle = 'article';
-    $this->bundle = 'node__comment_article';
+    $this->bundle = 'comment_article';
     $this->testLanguageSelector = FALSE;
     $this->subject = $this->randomName();
     parent::setUp();
@@ -52,14 +52,14 @@ function setupBundle() {
     parent::setupBundle();
     $this->drupalCreateContentType(array('type' => $this->nodeBundle, 'name' => $this->nodeBundle));
     // Add a comment field to the article content type.
-    $this->container->get('comment.manager')->addDefaultField('node', 'article', 'comment_article');
+    $this->container->get('comment.manager')->addDefaultField('node', 'article', 'comment_article', CommentItemInterface::OPEN, 'comment_article');
     // Create a page content type.
     $this->drupalCreateContentType(array('type' => 'page', 'name' => 'page'));
     // Add a comment field to the page content type - this one won't be
     // translatable.
     $this->container->get('comment.manager')->addDefaultField('node', 'page', 'comment');
     // Mark this bundle as translatable.
-    content_translation_set_config('comment', 'node__comment_article', 'enabled', TRUE);
+    content_translation_set_config('comment', 'comment_article', 'enabled', TRUE);
   }
 
   /**
@@ -82,12 +82,8 @@ function setupTestFields() {
   /**
    * Overrides \Drupal\content_translation\Tests\ContentTranslationUITest::createEntity().
    */
-  protected function createEntity($values, $langcode, $node_bundle = 'node__comment_article') {
-    // The argument is called 'node_bundle' but its actually just the entity
-    // bundle. Comment entity's bundle is of the form
-    // {entity_type}__{field_name}. Based on the passed bundle we need to
-    // determine the type of node and the name of the comment field.
-    if ($node_bundle == 'node__comment_article') {
+  protected function createEntity($values, $langcode, $comment_type = 'comment_article') {
+    if ($comment_type == 'comment_article') {
       // This is the article node type, with the 'comment_article' field.
       $node_type = 'article';
       $field_name = 'comment_article';
@@ -105,9 +101,9 @@ protected function createEntity($values, $langcode, $node_bundle = 'node__commen
     ));
     $values['entity_id'] = $node->id();
     $values['entity_type'] = 'node';
-    $values['field_id'] = $node_bundle;
+    $values['field_name'] = $field_name;
     $values['uid'] = $node->getOwnerId();
-    return parent::createEntity($values, $langcode, $node_bundle);
+    return parent::createEntity($values, $langcode, $comment_type);
   }
 
   /**
@@ -157,7 +153,7 @@ function testTranslateLinkCommentAdminPage() {
     $this->drupalLogin($this->admin_user);
 
     $cid_translatable = $this->createEntity(array(), $this->langcodes[0]);
-    $cid_untranslatable = $this->createEntity(array(), $this->langcodes[0], 'node__comment');
+    $cid_untranslatable = $this->createEntity(array(), $this->langcodes[0], 'comment');
 
     // Verify translation links.
     $this->drupalGet('admin/content/comment');
diff --git a/core/modules/comment/src/Tests/CommentTypeTest.php b/core/modules/comment/src/Tests/CommentTypeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7005bc1e3c1da1020ce65e78174335e2ea2ecb51
--- /dev/null
+++ b/core/modules/comment/src/Tests/CommentTypeTest.php
@@ -0,0 +1,189 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Tests\CommentTypeTest.
+ */
+
+namespace Drupal\comment\Tests;
+use Drupal\comment\Entity\Comment;
+use Drupal\comment\Entity\CommentType;
+use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldInstanceConfig;
+use Drupal\node\Entity\Node;
+
+/**
+ * Tests related to custom comment types.
+ */
+class CommentTypeTest extends CommentTestBase {
+
+  /**
+   * Admin user
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $adminUser;
+
+  /**
+   * Permissions to grant admin user.
+   *
+   * @var array
+   */
+  protected $permissions = array(
+    'administer comments',
+    'administer comment fields',
+    'administer comment types',
+  );
+
+  /**
+   * Sets the test up.
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->adminUser = $this->drupalCreateUser($this->permissions);
+  }
+
+  /**
+   * Declares test information.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Comment types',
+      'description' => 'Ensures that comment type functions work correctly.',
+      'group' => 'Comment',
+    );
+  }
+
+  /**
+   * Tests creating a comment type programmatically and via a form.
+   */
+  public function testCommentTypeCreation() {
+    // Create a comment type programmatically.
+    $type = $this->createCommentType('other');
+
+    $comment_type = CommentType::load('other');
+    $this->assertTrue($comment_type, 'The new comment type has been created.');
+
+    // Login a test user.
+    $this->drupalLogin($this->adminUser);
+
+    $this->drupalGet('admin/structure/comment/manage/' . $type->id());
+    $this->assertResponse(200, 'The new comment type can be accessed at the edit form.');
+
+    // Create a comment type via the user interface.
+    $edit = array(
+      'id' => 'foo',
+      'label' => 'title for foo',
+      'description' => '',
+      'target_entity_type_id' => 'node',
+    );
+    $this->drupalPostForm('admin/structure/comment/types/add', $edit, t('Save'));
+    $comment_type = CommentType::load('foo');
+    $this->assertTrue($comment_type, 'The new comment type has been created.');
+
+    // Check that the comment type was created in site default language.
+    $default_langcode = \Drupal::languageManager()->getDefaultLanguage()->id;
+    $this->assertEqual($comment_type->langcode, $default_langcode);
+  }
+
+  /**
+   * Tests editing a comment type using the UI.
+   */
+  public function testCommentTypeEditing() {
+    $this->drupalLogin($this->adminUser);
+
+    $instance = FieldInstanceConfig::loadByName('comment', 'comment', 'comment_body');
+    $this->assertEqual($instance->getLabel(), 'Comment', 'Comment body field was found.');
+
+    // Change the comment type name.
+    $this->drupalGet('admin/structure/comment');
+    $edit = array(
+      'label' => 'Bar',
+    );
+    $this->drupalPostForm('admin/structure/comment/manage/comment', $edit, t('Save'));
+
+    $this->drupalGet('admin/structure/comment');
+    $this->assertRaw('Bar', 'New name was displayed.');
+    $this->clickLink('Manage fields');
+    $this->assertEqual(url('admin/structure/comment/manage/comment/fields', array('absolute' => TRUE)), $this->getUrl(), 'Original machine name was used in URL.');
+
+    // Remove the body field.
+    $this->drupalPostForm('admin/structure/comment/manage/comment/fields/comment.comment.comment_body/delete', array(), t('Delete'));
+    // Resave the settings for this type.
+    $this->drupalPostForm('admin/structure/comment/manage/comment', array(), t('Save'));
+    // Check that the body field doesn't exist.
+    $this->drupalGet('admin/structure/comment/manage/comment/fields');
+    $this->assertNoRaw('comment_body', 'Body field was not found.');
+  }
+
+  /**
+   * Tests deleting a comment type that still has content.
+   */
+  public function testCommentTypeDeletion() {
+    // Create a comment type programmatically.
+    $type = $this->createCommentType('foo');
+    $this->drupalCreateContentType(array('type' => 'page'));
+    \Drupal::service('comment.manager')->addDefaultField('node', 'page', 'foo', CommentItemInterface::OPEN, 'foo');
+    $field = FieldConfig::loadByName('node', 'foo');
+
+    $this->drupalLogin($this->adminUser);
+
+    // Create a node.
+    $node = Node::create(array(
+      'type' => 'page',
+      'title' => 'foo',
+    ));
+    $node->save();
+
+    // Add a new comment of this type.
+    $comment = Comment::create(array(
+      'comment_type' => 'foo',
+      'entity_type' => 'node',
+      'field_name' => 'foo',
+      'entity_id' => $node->id(),
+    ));
+    $comment->save();
+
+    // Attempt to delete the comment type, which should not be allowed.
+    $this->drupalGet('admin/structure/comment/manage/' . $type->id() . '/delete');
+    $this->assertRaw(
+      t('%label is used by 1 comment on your site. You can not remove this comment type until you have removed all of the %label comments.', array('%label' => $type->label())),
+      'The comment type will not be deleted until all comments of that type are removed.'
+    );
+    $this->assertRaw(
+      t('%label is used by the %field field on your site. You can not remove this comment type until you have removed the field.', array(
+        '%label' => 'foo',
+        '%field' => 'node.foo',
+      )),
+      'The comment type will not be deleted until all fields of that type are removed.'
+    );
+    $this->assertNoText(t('This action cannot be undone.'), 'The comment type deletion confirmation form is not available.');
+
+    // Delete the comment and the field.
+    $comment->delete();
+    $field->delete();
+    // Attempt to delete the comment type, which should now be allowed.
+    $this->drupalGet('admin/structure/comment/manage/' . $type->id() . '/delete');
+    $this->assertRaw(
+      t('Are you sure you want to delete %type?', array('%type' => $type->id())),
+      'The comment type is available for deletion.'
+    );
+    $this->assertText(t('This action cannot be undone.'), 'The comment type deletion confirmation form is available.');
+
+    // Test exception thrown when re-using an existing comment type.
+    try {
+      \Drupal::service('comment.manager')->addDefaultField('comment', 'comment', 'bar');
+      $this->fail('Exception not thrown.');
+    }
+    catch (\InvalidArgumentException $e) {
+      $this->pass('Exception thrown if attempting to re-use comment-type from another entity type.');
+    }
+
+    // Delete the comment type.
+    $this->drupalPostForm('admin/structure/comment/manage/' . $type->id() . '/delete', array(), t('Delete'));
+    $this->assertNull(CommentType::load($type->id()), 'Comment type deleted.');
+    $this->assertRaw(t('Comment type %label has been deleted.', array('%label' => $type->label())));
+  }
+
+}
diff --git a/core/modules/comment/src/Tests/CommentValidationTest.php b/core/modules/comment/src/Tests/CommentValidationTest.php
index b56ed6b10923d32b023b5cb377474de507fce1ad..b705b16031eedd32c75eef4767df87b7797e5b4b 100644
--- a/core/modules/comment/src/Tests/CommentValidationTest.php
+++ b/core/modules/comment/src/Tests/CommentValidationTest.php
@@ -47,11 +47,21 @@ public function setUp() {
    * Tests the comment validation constraints.
    */
   public function testValidation() {
+    // Add comment type.
+    $this->entityManager->getStorage('comment_type')->create(array(
+      'id' => 'comment',
+      'label' => 'comment',
+      'target_entity_type_id' => 'node',
+    ))->save();
+
     // Add comment field to content.
     $this->entityManager->getStorage('field_config')->create(array(
       'entity_type' => 'node',
       'name' => 'comment',
       'type' => 'comment',
+      'settings' => array(
+        'comment_type' => 'comment',
+      )
     ))->save();
 
     // Create a page node type.
diff --git a/core/modules/comment/tests/src/Routing/CommentBundleEnhancerTest.php b/core/modules/comment/tests/src/Routing/CommentBundleEnhancerTest.php
deleted file mode 100644
index 95fbe8f8db01bfd1112558c1c1034726f1d60337..0000000000000000000000000000000000000000
--- a/core/modules/comment/tests/src/Routing/CommentBundleEnhancerTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\comment\Tests\Routing\CommentBundleEnhancerTest.
- */
-namespace Drupal\comment\Tests\Routing;
-
-use Drupal\comment\Routing\CommentBundleEnhancer;
-use Drupal\Tests\UnitTestCase;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Tests the comment bundle enhancer route enhancer.
- *
- * @see \Drupal\comment\Routing\CommentBundleEnhancer
- */
-class CommentBundleEnhancerTest extends UnitTestCase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Comment route enhancer test',
-      'description' => 'Tests the comment route enhancer.',
-      'group' => 'Comment',
-    );
-  }
-
-  /**
-   * Data provider for testEnhancer().
-   *
-   * @see testEnhancer()
-   *
-   * @return array
-   *   An array of arrays containing strings:
-   *     - The bundle name.
-   *     - The commented entity type.
-   *     - The field name.
-   */
-  public function providerTestEnhancer() {
-    return array(
-      array(
-        'node__comment',
-        'comment',
-        'node',
-      ),
-      array(
-        'node__comment_forum__schnitzel',
-        'comment_forum__schnitzel',
-        'node',
-      ),
-      array(
-        'node__field_foobar',
-        FALSE,
-        FALSE
-      ),
-    );
-  }
-  /**
-   * Tests the enhancer method.
-   *
-   * @param string $bundle
-   *   The bundle name to test.
-   * @param string $field_name
-   *   The field name expected to be extracted from the bundle.
-   * @param string $commented_entity_type
-   *   The entity type expected to be extracted from the bundle.
-   *
-   * @see \Drupal\comment\Routing\CommentBundleEnhancer::enhancer()
-   *
-   * @group Drupal
-   * @group Routing
-   *
-   * @dataProvider providerTestEnhancer
-   */
-  public function testEnhancer($bundle, $field_name, $commented_entity_type) {
-    $entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
-    $entity_manager->expects($this->any())
-      ->method('getBundleInfo')
-      ->will($this->returnValue(array(
-        'node__comment' => array(),
-        // Test two sets of __.
-        'node__comment_forum__schnitzel' => array(),
-      )));
-    $route_enhancer = new CommentBundleEnhancer($entity_manager);
-
-    // Test the enhancer.
-    $request = new Request();
-    $defaults = array('bundle' => $bundle);
-    $new_defaults = $route_enhancer->enhance($defaults, $request);
-    if ($commented_entity_type) {
-      // A valid comment bundle.
-      $this->assertEquals($new_defaults['field_name'], $field_name);
-      $this->assertEquals($new_defaults['commented_entity_type'], $commented_entity_type);
-    }
-    else {
-      // Non-comment bundle.
-      $this->assertTrue(empty($new_defaults['field_name']));
-      $this->assertTrue(empty($new_defaults['commented_entity_type']));
-    }
-  }
-
-}
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php
index 8f3b8032e0a79458af3e0bb95325882d341a0a50..084900ce93fa02d1123ac9d6ea50e3381ad35120 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php
@@ -7,7 +7,8 @@
 
 namespace Drupal\content_translation\Tests;
 
-use Drupal\Core\Language\LanguageInterface;
+use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
+use Drupal\Core\Language\Language;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\simpletest\WebTestBase;
 
@@ -38,9 +39,9 @@ function setUp() {
     // bundles.
     $this->drupalCreateContentType(array('type' => 'article'));
     $this->drupalCreateContentType(array('type' => 'page'));
-    $this->container->get('comment.manager')->addDefaultField('node', 'article', 'comment_article');
+    $this->container->get('comment.manager')->addDefaultField('node', 'article', 'comment_article', CommentItemInterface::OPEN, 'comment_article');
 
-    $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer languages', 'administer content translation', 'administer content types', 'administer node fields', 'administer comment fields'));
+    $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer languages', 'administer content translation', 'administer content types', 'administer node fields', 'administer comment fields', 'administer comments', 'administer comment types'));
     $this->drupalLogin($admin_user);
   }
 
@@ -54,21 +55,21 @@ function testSettingsUI() {
     $this->assertText('Configure language and translation support for content.');
     // Test that the translation settings are ignored if the bundle is marked
     // translatable but the entity type is not.
-    $edit = array('settings[comment][node__comment_article][translatable]' => TRUE);
+    $edit = array('settings[comment][comment_article][translatable]' => TRUE);
     $this->assertSettings('comment', NULL, FALSE, $edit);
 
     // Test that the translation settings are ignored if only a field is marked
     // as translatable and not the related entity type and bundle.
-    $edit = array('settings[comment][node__comment_article][fields][comment_body]' => TRUE);
+    $edit = array('settings[comment][comment_article][fields][comment_body]' => TRUE);
     $this->assertSettings('comment', NULL, FALSE, $edit);
 
     // Test that the translation settings are not stored if an entity type and
     // bundle are marked as translatable but no field is.
     $edit = array(
       'entity_types[comment]' => TRUE,
-      'settings[comment][node__comment_article][translatable]' => TRUE,
+      'settings[comment][comment_article][translatable]' => TRUE,
     );
-    $this->assertSettings('comment', 'node__comment_article', FALSE, $edit);
+    $this->assertSettings('comment', 'comment_article', FALSE, $edit);
     $xpath_err = '//div[contains(@class, "error")]';
     $this->assertTrue($this->xpath($xpath_err), 'Enabling translation only for entity bundles generates a form error.');
 
@@ -76,36 +77,36 @@ function testSettingsUI() {
     // language is set as default and the language selector is hidden.
     $edit = array(
       'entity_types[comment]' => TRUE,
-      'settings[comment][node__comment_article][settings][language][langcode]' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
-      'settings[comment][node__comment_article][settings][language][language_show]' => FALSE,
-      'settings[comment][node__comment_article][translatable]' => TRUE,
-      'settings[comment][node__comment_article][fields][comment_body]' => TRUE,
+      'settings[comment][comment_article][settings][language][langcode]' => Language::LANGCODE_NOT_SPECIFIED,
+      'settings[comment][comment_article][settings][language][language_show]' => FALSE,
+      'settings[comment][comment_article][translatable]' => TRUE,
+      'settings[comment][comment_article][fields][comment_body]' => TRUE,
     );
-    $this->assertSettings('comment', 'node__comment_article', FALSE, $edit);
+    $this->assertSettings('comment', 'comment_article', FALSE, $edit);
     $this->assertTrue($this->xpath($xpath_err), 'Enabling translation with a fixed non-configurable language generates a form error.');
 
     // Test that a field shared among different bundles can be enabled without
     // needing to make all the related bundles translatable.
     $edit = array(
       'entity_types[comment]' => TRUE,
-      'settings[comment][node__comment_article][settings][language][langcode]' => 'current_interface',
-      'settings[comment][node__comment_article][settings][language][language_show]' => TRUE,
-      'settings[comment][node__comment_article][translatable]' => TRUE,
-      'settings[comment][node__comment_article][fields][comment_body]' => TRUE,
+      'settings[comment][comment_article][settings][language][langcode]' => 'current_interface',
+      'settings[comment][comment_article][settings][language][language_show]' => TRUE,
+      'settings[comment][comment_article][translatable]' => TRUE,
+      'settings[comment][comment_article][fields][comment_body]' => TRUE,
     );
-    $this->assertSettings('comment', 'node__comment_article', TRUE, $edit);
+    $this->assertSettings('comment', 'comment_article', TRUE, $edit);
     $field = FieldConfig::loadByName('comment', 'comment_body');
     $this->assertTrue($field->isTranslatable(), 'Comment body is translatable.');
 
     // Test that language settings are correctly stored.
-    $language_configuration = language_get_default_configuration('comment', 'node__comment_article');
+    $language_configuration = language_get_default_configuration('comment', 'comment_article');
     $this->assertEqual($language_configuration['langcode'], 'current_interface', 'The default language for article comments is set to the current interface language.');
     $this->assertTrue($language_configuration['language_show'], 'The language selector for article comments is shown.');
 
-    // Verify language widget appears on node type form.
-    $this->drupalGet('admin/structure/comments/manage/node__comment_article/fields/comment.node__comment_article.comment_body/field');
-    $this->assertField('field[translatable]');
-    $this->assertFieldChecked('edit-field-translatable');
+    // Verify language widget appears on comment type form.
+    $this->drupalGet('admin/structure/comment/manage/comment_article');
+    $this->assertField('language_configuration[content_translation]');
+    $this->assertFieldChecked('edit-language-configuration-content-translation');
 
     // Verify that translation may be enabled for the article content type.
     $edit = array(
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
index e3669de43834e4b9dd722f823998f2b16cc2a9c5..615ca1e236c25eb48167a4dde856dab92c847023 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
@@ -83,7 +83,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $element = array();
 
     $element['datetime_type'] = array(
diff --git a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
index 8dd6f13a46d53fe4ce0ef7af81f2c74f393d94c8..cabf660aeb66244924048173fbd09f9e3102a421 100644
--- a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
+++ b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
@@ -159,7 +159,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $element['target_type'] = array(
       '#type' => 'select',
       '#title' => t('Type of item to reference'),
diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceSelectionAccessTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceSelectionAccessTest.php
index 4f7b28a5293e81eb68a4fc521e7d042a49d1783c..368c1d2bf774cca2e0ba3376b8e0b8887447c983 100644
--- a/core/modules/entity_reference/src/Tests/EntityReferenceSelectionAccessTest.php
+++ b/core/modules/entity_reference/src/Tests/EntityReferenceSelectionAccessTest.php
@@ -452,7 +452,7 @@ public function testCommentHandler() {
           array(NULL, 'CONTAINS'),
         ),
         'result' => array(
-          'node__comment' => array(
+          'comment' => array(
             $comments['published_published']->cid->value => $comment_labels['published_published'],
           ),
         ),
@@ -462,7 +462,7 @@ public function testCommentHandler() {
           array('Published', 'CONTAINS'),
         ),
         'result' => array(
-          'node__comment' => array(
+          'comment' => array(
             $comments['published_published']->cid->value => $comment_labels['published_published'],
           ),
         ),
@@ -491,7 +491,7 @@ public function testCommentHandler() {
           array(NULL, 'CONTAINS'),
         ),
         'result' => array(
-          'node__comment' => array(
+          'comment' => array(
             $comments['published_published']->cid->value => $comment_labels['published_published'],
             $comments['published_unpublished']->cid->value => $comment_labels['published_unpublished'],
           ),
@@ -509,7 +509,7 @@ public function testCommentHandler() {
           array(NULL, 'CONTAINS'),
         ),
         'result' => array(
-          'node__comment' => array(
+          'comment' => array(
             $comments['published_published']->cid->value => $comment_labels['published_published'],
             $comments['published_unpublished']->cid->value => $comment_labels['published_unpublished'],
             $comments['unpublished_published']->cid->value => $comment_labels['unpublished_published'],
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
index e215833f540dfd4c37912355626f5bc492f933d4..e21b180de2ff59e5170971b32525b87bcdfde410 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
@@ -76,7 +76,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $form['test_field_setting'] = array(
       '#type' => 'textfield',
       '#title' => t('Field test field setting'),
diff --git a/core/modules/field_ui/src/Form/FieldEditForm.php b/core/modules/field_ui/src/Form/FieldEditForm.php
index 068bd71072305ea8adf3b2cca0aaa05c72bd2ab3..68e6849f496753a0304089b75c8a377120d693f1 100644
--- a/core/modules/field_ui/src/Form/FieldEditForm.php
+++ b/core/modules/field_ui/src/Form/FieldEditForm.php
@@ -151,6 +151,8 @@ public function buildForm(array $form, array &$form_state, FieldInstanceConfigIn
 
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Save field settings'));
+    $form['#submit'][] = array($this, 'submitForm');
+    $form['#validate'][] = array($this, 'validateForm');
     return $form;
   }
 
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
index 27ce2abf4a5742a12ede3743575831a63ebba9c0..7f479dd30336de850ce0b37dc18161203d86fad7 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
@@ -106,7 +106,7 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $element = array();
 
     $element['#attached']['library'][] = 'file/drupal.file';
diff --git a/core/modules/file/src/Tests/FileFieldWidgetTest.php b/core/modules/file/src/Tests/FileFieldWidgetTest.php
index 26572897365e40b979e716edb9fc4ab243c2dbd7..3978501a0c4d732841e469baf44d67add934398a 100644
--- a/core/modules/file/src/Tests/FileFieldWidgetTest.php
+++ b/core/modules/file/src/Tests/FileFieldWidgetTest.php
@@ -258,7 +258,7 @@ function testPrivateFileComment() {
       'fields[_add_new_field][field_name]' => $name = strtolower($this->randomName()),
       'fields[_add_new_field][type]' => 'file',
     );
-    $this->drupalPostForm('admin/structure/comments/manage/node__comment/fields', $edit, t('Save'));
+    $this->drupalPostForm('admin/structure/comment/manage/comment/fields', $edit, t('Save'));
     $edit = array('field[settings][uri_scheme]' => 'private');
     $this->drupalPostForm(NULL, $edit, t('Save field settings'));
     $this->drupalPostForm(NULL, array(), t('Save settings'));
diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install
index dafedba47ea99e39ab5cfff694632e318c70b9a4..1f5ed4fa2ffeb85f67e62516d2829710f99a2877 100644
--- a/core/modules/forum/forum.install
+++ b/core/modules/forum/forum.install
@@ -4,6 +4,8 @@
  * @file
  * Install, update, and uninstall functions for the Forum module.
  */
+
+use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\field\Entity\FieldConfig;
 
 /**
@@ -84,7 +86,7 @@ function forum_install() {
       'include_deleted' => FALSE,
     ));
     if (empty($fields)) {
-      Drupal::service('comment.manager')->addDefaultField('node', 'forum', 'comment_forum');
+      Drupal::service('comment.manager')->addDefaultField('node', 'forum', 'comment_forum', CommentItemInterface::OPEN, 'comment_forum');
     }
   }
 }
diff --git a/core/modules/forum/src/ForumIndexStorage.php b/core/modules/forum/src/ForumIndexStorage.php
index 2d257a43c3f6d1878ed3586ed7231dfdfc1491f4..d73280603a755de962ffc1c5a9577b3fa58d5cd9 100644
--- a/core/modules/forum/src/ForumIndexStorage.php
+++ b/core/modules/forum/src/ForumIndexStorage.php
@@ -96,14 +96,14 @@ public function update(NodeInterface $node) {
    */
   public function updateIndex(NodeInterface $node) {
     $nid = $node->id();
-    $count = $this->database->query("SELECT COUNT(cid) FROM {comment} c INNER JOIN {forum_index} i ON c.entity_id = i.nid WHERE c.entity_id = :nid AND c.field_id = 'node__comment_forum' AND c.entity_type = 'node' AND c.status = :status", array(
+    $count = $this->database->query("SELECT COUNT(cid) FROM {comment} c INNER JOIN {forum_index} i ON c.entity_id = i.nid WHERE c.entity_id = :nid AND c.field_name = 'comment_forum' AND c.entity_type = 'node' AND c.status = :status", array(
       ':nid' => $nid,
       ':status' => CommentInterface::PUBLISHED,
     ))->fetchField();
 
     if ($count > 0) {
       // Comments exist.
-      $last_reply = $this->database->queryRange("SELECT cid, name, created, uid FROM {comment} WHERE entity_id = :nid AND field_id = 'node__comment_forum' AND entity_type = 'node' AND status = :status ORDER BY cid DESC", 0, 1, array(
+      $last_reply = $this->database->queryRange("SELECT cid, name, created, uid FROM {comment} WHERE entity_id = :nid AND field_name = 'comment_forum' AND entity_type = 'node' AND status = :status ORDER BY cid DESC", 0, 1, array(
         ':nid' => $nid,
         ':status' => CommentInterface::PUBLISHED,
       ))->fetchObject();
diff --git a/core/modules/forum/src/ForumManager.php b/core/modules/forum/src/ForumManager.php
index 8b87680e7b7b2a58fa91303c3cec972ae40a48f9..1609899f745b9c43903a7379dccaff18ff0f3dcb 100644
--- a/core/modules/forum/src/ForumManager.php
+++ b/core/modules/forum/src/ForumManager.php
@@ -169,7 +169,7 @@ public function getTopics($tid, AccountInterface $account) {
         ->extend('Drupal\Core\Database\Query\TableSortExtender');
       $query->fields('n', array('nid'));
 
-      $query->join('comment_entity_statistics', 'ces', "n.nid = ces.entity_id AND ces.field_id = 'node__comment_forum' AND ces.entity_type = 'node'");
+      $query->join('comment_entity_statistics', 'ces', "n.nid = ces.entity_id AND ces.field_name = 'comment_forum' AND ces.entity_type = 'node'");
       $query->fields('ces', array(
         'cid',
         'last_comment_uid',
@@ -340,7 +340,7 @@ protected function getLastPost($tid) {
     // Query "Last Post" information for this forum.
     $query = $this->connection->select('node_field_data', 'n');
     $query->join('forum', 'f', 'n.vid = f.vid AND f.tid = :tid', array(':tid' => $tid));
-    $query->join('comment_entity_statistics', 'ces', "n.nid = ces.entity_id AND ces.field_id = 'node__comment_forum' AND ces.entity_type = 'node'");
+    $query->join('comment_entity_statistics', 'ces', "n.nid = ces.entity_id AND ces.field_name = 'comment_forum' AND ces.entity_type = 'node'");
     $query->join('users', 'u', 'ces.last_comment_uid = u.uid');
     $query->addExpression('CASE ces.last_comment_uid WHEN 0 THEN ces.last_comment_name ELSE u.name END', 'last_comment_name');
 
@@ -378,7 +378,7 @@ protected function getForumStatistics($tid) {
     if (empty($this->forumStatistics)) {
       // Prime the statistics.
       $query = $this->connection->select('node_field_data', 'n');
-      $query->join('comment_entity_statistics', 'ces', "n.nid = ces.entity_id AND ces.field_id = 'node__comment_forum' AND ces.entity_type = 'node'");
+      $query->join('comment_entity_statistics', 'ces', "n.nid = ces.entity_id AND ces.field_name = 'comment_forum' AND ces.entity_type = 'node'");
       $query->join('forum', 'f', 'n.vid = f.vid');
       $query->addExpression('COUNT(n.nid)', 'topic_count');
       $query->addExpression('SUM(ces.comment_count)', 'comment_count');
diff --git a/core/modules/forum/src/Tests/ForumUninstallTest.php b/core/modules/forum/src/Tests/ForumUninstallTest.php
index 130143f977832d8c86d86a3d89544d034f32ab9a..3b3887696d0e0165d3e0e116e0c9d77102aa653c 100644
--- a/core/modules/forum/src/Tests/ForumUninstallTest.php
+++ b/core/modules/forum/src/Tests/ForumUninstallTest.php
@@ -77,7 +77,7 @@ function testForumUninstallWithField() {
     // We want to test the handling of removing the forum comment field, so we
     // ensure there is at least one other comment field attached to a node type
     // so that comment_entity_load() runs for nodes.
-    \Drupal::service('comment.manager')->addDefaultField('node', 'forum', 'another_comment_field', CommentItemInterface::OPEN);
+    \Drupal::service('comment.manager')->addDefaultField('node', 'forum', 'another_comment_field', CommentItemInterface::OPEN, 'another_comment_field');
 
     $this->drupalGet('node/' . $node->nid->value);
     $this->assertResponse(200);
diff --git a/core/modules/hal/src/Tests/EntityTest.php b/core/modules/hal/src/Tests/EntityTest.php
index 8bc3fed8b0624c65afd0ebd4f1d80a8e7751013e..d9a9004e95cf953717d7a2bcfd0d5797630d4fff 100644
--- a/core/modules/hal/src/Tests/EntityTest.php
+++ b/core/modules/hal/src/Tests/EntityTest.php
@@ -54,6 +54,15 @@ public function testNode() {
     $user = entity_create('user', array('name' => $this->randomName()));
     $user->save();
 
+    // Add comment type.
+    $this->container->get('entity.manager')->getStorage('comment_type')->create(array(
+      'id' => 'comment',
+      'label' => 'comment',
+      'target_entity_type_id' => 'node',
+    ))->save();
+
+    $this->container->get('comment.manager')->addDefaultField('node', 'example_type');
+
     $node = entity_create('node', array(
       'title' => $this->randomName(),
       'uid' => $user->id(),
@@ -129,6 +138,15 @@ public function testComment() {
     $user = entity_create('user', array('name' => $this->randomName()));
     $user->save();
 
+    // Add comment type.
+    $this->container->get('entity.manager')->getStorage('comment_type')->create(array(
+      'id' => 'comment',
+      'label' => 'comment',
+      'target_entity_type_id' => 'node',
+    ))->save();
+
+    $this->container->get('comment.manager')->addDefaultField('node', 'example_type');
+
     $node = entity_create('node', array(
       'title' => $this->randomName(),
       'uid' => $user->id(),
@@ -143,8 +161,6 @@ public function testComment() {
     ));
     $node->save();
 
-    $this->container->get('comment.manager')->addDefaultField('node', 'example_type');
-
     $comment = entity_create('comment', array(
       'uid' => $user->id(),
       'subject' => $this->randomName(),
diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
index f94c51df16627cb13df44ca942fbd2dd713e3b2f..49d2e25894d2e48d03d685ffa0cbf08f91f4ab70 100644
--- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -152,7 +152,7 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $element = array();
 
     // We need the field-level 'default_image' setting, and $this->getSettings()
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml
index 961cb406b4164de244e29081a2934eed3953b614..34e681e9d6869b57b848f276eb9600cd9176722d 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment.yml
@@ -3,7 +3,8 @@ label: Drupal 6 comments
 source:
   plugin: d6_comment
   constants:
-    field_id: node__comment
+    field_name: comment
+    comment_type: comment
     entity_type: node
 process:
   cid: cid
@@ -19,7 +20,8 @@ process:
     migration: d6_node
     source: nid
   entity_type: constants.entity_type
-  field_id: constants.field_id
+  field_name: constants.field_name
+  comment_type: constants.comment_type
   subject: subject
   uid:
     -
@@ -44,6 +46,8 @@ process:
 destination:
   plugin: entity:comment
 migration_dependencies:
+  optional:
+    - d6_comment_type
   required:
     - d6_node
     - d6_user
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field.yml
index 5c4dd3be275d4373fe8fce29b42043cd6192675e..2a5ccc4cc44b8ad7eb9205aa7402c40e511b291b 100644
--- a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field.yml
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_field.yml
@@ -7,10 +7,13 @@ source:
     type: comment
     id: node.comment
     name: comment
+    settings:
+      content_type: comment
 process:
   entity_type: constants.entity_type
   id: constants.id
   name: constants.name
   type: constants.type
+  settings: constants.settings
 destination:
   plugin: entity:field_config
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_type.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_type.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6bd490b5619e020bc90f30b202c7421f65167a16
--- /dev/null
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d6_comment_type.yml
@@ -0,0 +1,25 @@
+id: d6_comment_type
+label: Drupal 6 comment type
+source:
+  plugin: variable
+  variables:
+  # Ensure that we get at least one row to process by using variables that exist
+  # on every Drupal 6 site. We just need a single one of these, but include a
+  # few to be sure.
+    - site_name
+    - menu_expanded
+    - menu_masks
+    - css_js_query_string
+    - clean_url
+  constants:
+    entity_type: node
+    id: comment
+    label: comment
+    description: comment
+process:
+  target_entity_type_id: constants.entity_type
+  id: constants.id
+  label: constants.label
+  description: constants.description
+destination:
+  plugin: entity:comment_type
diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateCommentTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateCommentTest.php
index c8cb1a6ad4fcf78ba736b0796c357a221c3bc829..d07b02b9f9817428aa30064f2a309293a727da9f 100644
--- a/core/modules/migrate_drupal/src/Tests/d6/MigrateCommentTest.php
+++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateCommentTest.php
@@ -13,7 +13,7 @@
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
 /**
- * Tests the Drupal 6 to Drupal 6 comment migration.
+ * Tests the Drupal 6 to Drupal 8 comment migration.
  */
 class MigrateCommentTest extends MigrateDrupalTestBase {
 
@@ -37,6 +37,12 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     entity_create('node_type', array('type' => 'page'))->save();
+    $this->container->get('entity.manager')->getStorage('comment_type')->create(array(
+      'id' => 'comment',
+      'label' => 'comment',
+      'target_entity_type_id' => 'node',
+    ))->save();
+
     $node = entity_create('node', array(
       'type' => 'page',
       'nid' => 1,
@@ -65,7 +71,7 @@ public function setUp() {
   }
 
   /**
-   * Tests the Drupal 6 to Drupal 6 comment migration.
+   * Tests the Drupal 6 to Drupal 8 comment migration.
    */
   public function testComments() {
     /** @var Comment $comment */
diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateCommentTypeTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateCommentTypeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e31159e84d2c886ff6e3273040a61f421ff201fd
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateCommentTypeTest.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\d6\MigrateCommentTypeTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\d6;
+
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
+
+/**
+ * Tests the Drupal 6 to Drupal 8 comment type migration.
+ */
+class MigrateCommentTypeTest extends MigrateDrupalTestBase {
+
+  static $modules = array('node', 'comment');
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name'  => 'Migrate comment type.',
+      'description'  => 'Upgrade comment type.',
+      'group' => 'Migrate Drupal',
+    );
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    /** @var \Drupal\migrate\entity\Migration $migration */
+    $migration = entity_load('migration', 'd6_comment_type');
+
+    $dumps = array(
+      $this->getDumpDirectory() . '/Drupal6SystemSite.php',
+    );
+    $this->prepare($migration, $dumps);
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+  }
+
+  /**
+   * Tests the Drupal 6 to Drupal 8 comment type migration.
+   */
+  public function testCommentType() {
+    $comment_type = entity_load('comment_type', 'comment');
+    $this->assertEqual('node', $comment_type->getTargetEntityTypeId());
+  }
+}
diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6Test.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6Test.php
index 79f11da968bdc57dfaffd79f7ae749c26c6afcc8..592992e597f917ed9568f769b569180114a40f68 100644
--- a/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6Test.php
+++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6Test.php
@@ -61,6 +61,7 @@ class MigrateDrupal6Test extends MigrateFullDrupalTestBase {
     'd6_book_settings',
     'd6_cck_field_values:*',
     'd6_cck_field_revision:*',
+    'd6_comment_type',
     'd6_comment',
     'd6_comment_entity_display',
     'd6_comment_entity_form_display',
@@ -228,6 +229,7 @@ protected function getTestClassesList() {
       __NAMESPACE__ . '\MigrateBookConfigsTest',
       __NAMESPACE__ . '\MigrateCckFieldValuesTest',
       __NAMESPACE__ . '\MigrateCckFieldRevisionTest',
+      __NAMESPACE__ . '\MigrateCommentTypeTest',
       __NAMESPACE__ . '\MigrateCommentTest',
       __NAMESPACE__ . '\MigrateCommentVariableEntityDisplay',
       __NAMESPACE__ . '\MigrateCommentVariableEntityFormDisplay',
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListBooleanItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListBooleanItem.php
index 095c89cc62537d2427905ee7988648a428beac21..5d165852a0cf9f282d4cb042958598d8e2cc3bbb 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListBooleanItem.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListBooleanItem.php
@@ -102,7 +102,7 @@ public function isEmpty() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $allowed_values = $this->getSetting('allowed_values');
     $allowed_values_function = $this->getSetting('allowed_values_function');
 
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
index 64604e53a117bdd67d854dc1694884cbdb9ba8d8..d61aef11c31ea7e4f3f21b8b83b561aee653d3a2 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
@@ -72,7 +72,7 @@ public function isEmpty() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $allowed_values = $this->getSetting('allowed_values');
     $allowed_values_function = $this->getSetting('allowed_values_function');
 
diff --git a/core/modules/rdf/src/Tests/CommentAttributesTest.php b/core/modules/rdf/src/Tests/CommentAttributesTest.php
index d3cacfd970c1be1c848f2390afa4fb4bf76bc640..d58e44b5618b23e020dfd3f5bbc4f12f5da534af 100644
--- a/core/modules/rdf/src/Tests/CommentAttributesTest.php
+++ b/core/modules/rdf/src/Tests/CommentAttributesTest.php
@@ -68,7 +68,7 @@ public function setUp() {
     $user_mapping->setFieldMapping('homepage', array('properties' => array('foaf:page'), 'mapping_type' => 'rel'))->save();
 
     // Save comment mapping.
-    $mapping = rdf_get_mapping('comment', 'node__comment');
+    $mapping = rdf_get_mapping('comment', 'comment');
     $mapping->setBundleMapping(array('types' => array('sioc:Post', 'sioct:Comment')))->save();
     $field_mappings = array(
       'subject' => array(
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
index cc8ef7eda57e20fedfa22633e6a4a5894d4ecfe7..fb6a93e1b0ceb0fbed0ec8a542441a31091b7d4e 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
@@ -119,7 +119,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $vocabularies = entity_load_multiple('taxonomy_vocabulary');
     $options = array();
     foreach ($vocabularies as $vocabulary) {
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
index b2ba0a171ed62367c6ab9bdbb6035c7d601096e7..6bacea68ab2d892a6afa7b8505573c68f90e5336 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
@@ -78,7 +78,7 @@ public function getConstraints() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, array &$form_state, $has_data) {
     $element = array();
 
     $element['max_length'] = array(
diff --git a/core/profiles/standard/config/install/comment.type.comment.yml b/core/profiles/standard/config/install/comment.type.comment.yml
new file mode 100644
index 0000000000000000000000000000000000000000..651028791236a27ddace97e7508e66e7ff8c39da
--- /dev/null
+++ b/core/profiles/standard/config/install/comment.type.comment.yml
@@ -0,0 +1,6 @@
+id: comment
+label: 'Default comments'
+description: 'Allows commenting on content'
+target_entity_type_id: node
+status: true
+langcode: en
diff --git a/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml b/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml
index 70f25b1fa6647dbfc762119ea729c18b6d359a8b..00abf0c29139edc305a4c7cff6ebb87bc24e891f 100644
--- a/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml
+++ b/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml
@@ -1,6 +1,6 @@
-id: comment.node__comment
+id: comment.comment
 targetEntityType: comment
-bundle: node__comment
+bundle: comment
 types:
   - 'schema:Comment'
 fieldMappings:
@@ -27,3 +27,5 @@ fieldMappings:
 dependencies:
   module:
     - comment
+  entity:
+    - comment.type.comment