diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index d7107c5..d34d3f0 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -59,7 +59,15 @@ public function setOperation($operation) {
    * {@inheritdoc}
    */
   public function getBaseFormID() {
-    return $this->entity->entityType() . '_form';
+    // Assign ENTITYTYPE_form as base form ID to invoke corresponding
+    // hook_form_alter(), #validate, #submit, and #theme callbacks, but only if
+    // it is different from the actual form ID, since callbacks would be invoked
+    // twice otherwise.
+    $base_form_id = $this->entity->entityType() . '_form';
+    if ($base_form_id == $this->getFormID()) {
+      $base_form_id = '';
+    }
+    return $base_form_id;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityListController.php b/core/lib/Drupal/Core/Entity/EntityListController.php
index b5a5f9c..818ba2b 100644
--- a/core/lib/Drupal/Core/Entity/EntityListController.php
+++ b/core/lib/Drupal/Core/Entity/EntityListController.php
@@ -182,7 +182,9 @@ public function render() {
       '#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo['label'])),
     );
     foreach ($this->load() as $entity) {
-      $build['#rows'][$entity->id()] = $this->buildRow($entity);
+      if ($row = $this->buildRow($entity)) {
+        $build['#rows'][$entity->id()] = $row;
+      }
     }
     return $build;
   }
diff --git a/core/modules/book/book.install b/core/modules/book/book.install
index 7d70a02..610808b 100644
--- a/core/modules/book/book.install
+++ b/core/modules/book/book.install
@@ -6,14 +6,6 @@
  */
 
 /**
- * Implements hook_install().
- */
-function book_install() {
-  // Add the node type.
-  _book_install_type_create();
-}
-
-/**
  * Implements hook_uninstall().
  */
 function book_uninstall() {
@@ -25,28 +17,6 @@ function book_uninstall() {
 }
 
 /**
- * Creates the book content type.
- */
-function _book_install_type_create() {
-  // Create an additional node type.
-  $book_node_type = array(
-    'type' => 'book',
-    'name' => t('Book page'),
-    'base' => 'node_content',
-    'description' => t('<em>Books</em> have a built-in hierarchical navigation. Use for handbooks or tutorials.'),
-    'custom' => 1,
-    'modified' => 1,
-    'locked' => 0,
-  );
-
-  $book_node_type = node_type_set_defaults($book_node_type);
-  node_type_save($book_node_type);
-  node_add_body_field($book_node_type);
-  // Default to not promoted.
-  variable_set('node_options_book', array('status'));
-}
-
-/**
  * Implements hook_schema().
  */
 function book_schema() {
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 1fe04c8..3462abf 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\node\NodeTypeInterface;
 use Drupal\Core\Language\Language;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\Core\Template\Attribute;
@@ -1230,25 +1231,24 @@ function book_type_is_allowed($type) {
  * Updates book.settings configuration object if the machine-readable name of a
  * node type is changed.
  */
-function book_node_type_update($type) {
-  if (!empty($type->old_type) && $type->old_type != $type->type) {
+function book_node_type_update(NodeTypeInterface $type) {
+  if ($type->getOriginalID() != $type->id()) {
     $config = config('book.settings');
     // Update the list of node types that are allowed to be added to books.
     $allowed_types = $config->get('allowed_types');
-    $old_key = array_search($type->old_type, $allowed_types);
+    $old_key = array_search($type->getOriginalID(), $allowed_types);
+
     if ($old_key !== FALSE) {
-      // Replace the old machine-readable name with the new machine-readable
-      // name.
-      $allowed_types[$old_key] = $type->type;
+      $allowed_types[$old_key] = $type->id();
       // Ensure that the allowed_types array is sorted consistently.
-      // @see book_admin_settings_submit()
+      // @see BookSettingsForm::submitForm()
       sort($allowed_types);
       $config->set('allowed_types', $allowed_types);
     }
 
     // Update the setting for the "Add child page" link.
-    if ($config->get('child_type') == $type->old_type) {
-      $config->set('child_type', $type->type);
+    if ($config->get('child_type') == $type->getOriginalID()) {
+      $config->set('child_type', $type->id());
     }
     $config->save();
   }
diff --git a/core/modules/book/config/node.type.book.yml b/core/modules/book/config/node.type.book.yml
new file mode 100644
index 0000000..426778d
--- /dev/null
+++ b/core/modules/book/config/node.type.book.yml
@@ -0,0 +1,19 @@
+type: book
+uuid: c5ca890d-7db7-4c45-bf0f-0a12430923ff
+name: 'Book page'
+description: '<em>Books</em> have a built-in hierarchical navigation. Use for handbooks or tutorials.'
+help: ''
+has_title: '1'
+title_label: Title
+settings:
+  node:
+    preview: '1'
+    options:
+      status: status
+      # Not promoted to front page.
+      promote: '0'
+      sticky: '0'
+      revision: '0'
+    submitted: '1'
+status: '1'
+langcode: und
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index 71b2cf0..efaf9f3 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -69,9 +69,6 @@ function comment_modules_enabled($modules) {
   // hook_node_type_insert() is used to create body fields while the comment
   // module is enabled.
   if (in_array('comment', $modules)) {
-    // Ensure that the list of node types reflects newly enabled modules.
-    node_types_rebuild();
-
     // Create comment body fields for each node type, if needed.
     foreach (node_type_get_types() as $type => $info) {
       _comment_body_field_create($info);
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 2466ce7..7cd4e70 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -9,6 +9,7 @@
  * book page, etc.
  */
 
+use Drupal\node\NodeTypeInterface;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Entity\EntityInterface;
@@ -114,25 +115,6 @@ function comment_entity_bundle_info() {
 }
 
 /**
- * Loads the comment bundle name corresponding a given content type.
- *
- * This function is used as a menu loader callback in comment_menu().
- *
- * @param $name
- *   The machine name of the node type whose comment fields are to be edited.
- *
- * @return
- *   The comment bundle name corresponding to the node type.
- *
- * @see comment_menu_alter()
- */
-function comment_node_type_load($name) {
-  if ($type = node_type_load($name)) {
-    return 'comment_node_' . $type->type;
-  }
-}
-
-/**
  * Entity URI callback.
  */
 function comment_uri(Comment $comment) {
@@ -277,10 +259,10 @@ function comment_menu_alter(&$items) {
 
   // Adjust the Field UI tabs on admin/structure/types/manage/[node-type].
   // See comment_entity_bundle_info().
-  $items['admin/structure/types/manage/%/comment/fields']['title'] = 'Comment fields';
-  $items['admin/structure/types/manage/%/comment/fields']['weight'] = 3;
-  $items['admin/structure/types/manage/%/comment/display']['title'] = 'Comment display';
-  $items['admin/structure/types/manage/%/comment/display']['weight'] = 4;
+  $items['admin/structure/types/manage/{bundle}/comment/fields']['title'] = 'Comment fields';
+  $items['admin/structure/types/manage/{bundle}/comment/fields']['weight'] = 3;
+  $items['admin/structure/types/manage/{bundle}/comment/display']['title'] = 'Comment display';
+  $items['admin/structure/types/manage/{bundle}/comment/display']['weight'] = 4;
 }
 
 /**
@@ -309,9 +291,9 @@ function comment_node_type_insert($info) {
 /**
  * Implements hook_node_type_update().
  */
-function comment_node_type_update($info) {
-  if (!empty($info->old_type) && $info->type != $info->old_type) {
-    entity_invoke_bundle_hook('rename', 'comment', 'comment_node_' . $info->old_type, 'comment_node_' . $info->type);
+function comment_node_type_update(NodeTypeInterface $type) {
+  if ($type->original->id() != $type->id()) {
+    entity_invoke_bundle_hook('rename', 'comment', 'comment_node_' . $type->original->id(), 'comment_node_' . $type->id());
   }
 }
 
@@ -990,6 +972,7 @@ function comment_view_multiple($comments, $view_mode = 'full', $langcode = NULL)
  */
 function comment_form_node_type_form_alter(&$form, $form_state) {
   if (isset($form['type'])) {
+    $node_type = $form_state['controller']->getEntity();
     $form['comment'] = array(
       '#type' => 'details',
       '#title' => t('Comment settings'),
@@ -1008,7 +991,7 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     $form['comment']['comment'] = array(
       '#type' => 'select',
       '#title' => t('Default comment setting for new content'),
-      '#default_value' => variable_get('comment_' . $form['#node_type']->type, COMMENT_NODE_OPEN),
+      '#default_value' => variable_get('comment_' . $node_type->id(), COMMENT_NODE_OPEN),
       '#options' => array(
         COMMENT_NODE_OPEN => t('Open'),
         COMMENT_NODE_CLOSED => t('Closed'),
@@ -1018,19 +1001,19 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     $form['comment']['comment_default_mode'] = array(
       '#type' => 'checkbox',
       '#title' => t('Threading'),
-      '#default_value' => variable_get('comment_default_mode_' . $form['#node_type']->type, COMMENT_MODE_THREADED),
+      '#default_value' => variable_get('comment_default_mode_' . $node_type->id(), COMMENT_MODE_THREADED),
       '#description' => t('Show comment replies in a threaded list.'),
     );
     $form['comment']['comment_default_per_page'] = array(
       '#type' => 'select',
       '#title' => t('Comments per page'),
-      '#default_value' => variable_get('comment_default_per_page_' . $form['#node_type']->type, 50),
+      '#default_value' => variable_get('comment_default_per_page_' . $node_type->id(), 50),
       '#options' => _comment_per_page(),
     );
     $form['comment']['comment_anonymous'] = array(
       '#type' => 'select',
       '#title' => t('Anonymous commenting'),
-      '#default_value' => variable_get('comment_anonymous_' . $form['#node_type']->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT),
+      '#default_value' => variable_get('comment_anonymous_' . $node_type->id(), COMMENT_ANONYMOUS_MAYNOT_CONTACT),
       '#options' => array(
         COMMENT_ANONYMOUS_MAYNOT_CONTACT => t('Anonymous posters may not enter their contact information'),
         COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'),
@@ -1041,17 +1024,17 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     $form['comment']['comment_subject_field'] = array(
       '#type' => 'checkbox',
       '#title' => t('Allow comment title'),
-      '#default_value' => variable_get('comment_subject_field_' . $form['#node_type']->type, 1),
+      '#default_value' => variable_get('comment_subject_field_' . $node_type->id(), 1),
     );
     $form['comment']['comment_form_location'] = array(
       '#type' => 'checkbox',
       '#title' => t('Show reply form on the same page as comments'),
-      '#default_value' => variable_get('comment_form_location_' . $form['#node_type']->type, COMMENT_FORM_BELOW),
+      '#default_value' => variable_get('comment_form_location_' . $node_type->id(), COMMENT_FORM_BELOW),
     );
     $form['comment']['comment_preview'] = array(
       '#type' => 'radios',
       '#title' => t('Preview comment'),
-      '#default_value' => variable_get('comment_preview_' . $form['#node_type']->type, DRUPAL_OPTIONAL),
+      '#default_value' => variable_get('comment_preview_' . $node_type->id(), DRUPAL_OPTIONAL),
       '#options' => array(
         DRUPAL_DISABLED => t('Disabled'),
         DRUPAL_OPTIONAL => t('Optional'),
@@ -1062,7 +1045,7 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     if (module_exists('content_translation')) {
       $comment_form = $form;
       $comment_form_state['content_translation']['key'] = 'language_configuration';
-      $form['comment'] += content_translation_enable_widget('comment', 'comment_node_' . $form['#node_type']->type, $comment_form, $comment_form_state);
+      $form['comment'] += translation_entity_enable_widget('comment', 'comment_node_' . $node_type->id(), $comment_form, $comment_form_state);
       array_unshift($form['#submit'], 'comment_translation_configuration_element_submit');
     }
   }
@@ -1084,7 +1067,7 @@ function comment_translation_configuration_element_submit($form, &$form_state) {
   $key = 'language_configuration';
   $comment_form_state = array(
     'content_translation' => array('key' => $key),
-    'language' => array($key => array('entity_type' => 'comment', 'bundle' => 'comment_node_' . $form['#node_type']->type)),
+    'language' => array($key => array('entity_type' => 'comment', 'bundle' => 'comment_node_' . $form_state['controller']->getEntity()->id())),
     'values' => array($key => array('content_translation' => $form_state['values']['content_translation'])),
   );
   content_translation_language_configuration_element_submit($form, $comment_form_state);
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
index 24cb092..a29e967 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
@@ -202,19 +202,19 @@ public function testFieldComponent() {
    * Tests renaming and deleting a bundle.
    */
   public function testRenameDeleteBundle() {
-    $this->enableModules(array('field_sql_storage', 'field_test', 'node', 'system'));
-    $this->installSchema('node', array('node_type'));
+    $this->enableModules(array('field_sql_storage', 'field_test', 'node', 'system', 'text'));
     $this->installSchema('system', array('variable'));
+    $this->installSchema('node', array('node'));
 
     // Create a node bundle and display object.
-    node_type_save((object) array('type' => 'article'));
+    entity_create('node_type', array('type' => 'article'))->save();
     entity_get_display('node', 'article', 'default')->save();
 
     // Rename the article bundle and assert the entity display is renamed.
     $info = node_type_load('article');
     $info->old_type = 'article';
     $info->type = 'article_rename';
-    node_type_save($info);
+    $info->save();
     $old_display = entity_load('entity_display', 'node.article.default');
     $this->assertFalse($old_display);
     $new_display = entity_load('entity_display', 'node.article_rename.default');
@@ -222,7 +222,7 @@ public function testRenameDeleteBundle() {
     $this->assertEqual('node.article_rename.default', $new_display->id);
 
     // Delete the bundle.
-    node_type_delete('article_rename');
+    $info->delete();
     $display = entity_load('entity_display', 'node.article_rename.default');
     $this->assertFalse($display);
   }
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 63ea3f0..519d98c 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -1154,7 +1154,7 @@ function field_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
     }
   }
 
-  // Clear the cache.
+  // Clear the field cache.
   field_cache_clear();
 
   // Update bundle settings.
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
index 75d9e28..91a33d0 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
@@ -80,7 +80,6 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
     $this->installSchema('language', array('language'));
-    $this->installSchema('node', array('node_type'));
 
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
 
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 01afcbc..17e8ad0 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -267,13 +267,11 @@ function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
  */
 function field_ui_form_node_type_form_alter(&$form, $form_state) {
   // We want to display the button only on add page.
-  if (empty($form['#node_type']->type)) {
-    $form['actions']['save_continue'] = array(
-      '#type' => 'submit',
-      '#value' => t('Save and manage fields'),
-      '#weight' => 45,
-    );
-    $form['#submit'][] = 'field_ui_form_node_type_form_submit';
+  if ($form_state['controller']->getEntity()->isNew()) {
+    $form['actions']['save_continue'] = $form['actions']['submit'];
+    $form['actions']['save_continue']['#value'] = t('Save and manage fields');
+    $form['actions']['save_continue']['#weight'] = $form['actions']['save_continue']['#weight'] + 5;
+    $form['actions']['save_continue']['#submit'][] = 'field_ui_form_node_type_form_submit';
   }
 }
 
diff --git a/core/modules/forum/config/node.type.forum.yml b/core/modules/forum/config/node.type.forum.yml
new file mode 100644
index 0000000..7ffb0e7
--- /dev/null
+++ b/core/modules/forum/config/node.type.forum.yml
@@ -0,0 +1,19 @@
+type: forum
+uuid: c14b392d-0889-46bd-889e-a239e8b6cd89
+name: 'Forum topic'
+description: 'A <em>forum topic</em> starts a new discussion thread within a forum.'
+help: ''
+has_title: '1'
+title_label: Subject
+settings:
+  node:
+    preview: '1'
+    options:
+      status: status
+      # Not promoted to front page.
+      promote: '0'
+      sticky: '0'
+      revision: '0'
+    submitted: '1'
+status: '1'
+langcode: und
diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install
index 9f16099..e0219ff 100644
--- a/core/modules/forum/forum.install
+++ b/core/modules/forum/forum.install
@@ -11,11 +11,10 @@
 function forum_install() {
   // Set the weight of the forum.module to 1 so it is loaded after the taxonomy.module.
   module_set_weight('forum', 1);
-  // Forum topics are published by default, but do not have any other default
-  // options set (for example, they are not promoted to the front page).
-  // @todo Convert to default module configuration, once Node module's content
-  //   types are converted.
-  variable_set('node_options_forum', array('status'));
+  // Do not allow to delete the forum's node type machine name.
+  $locked = Drupal::state()->get('node.type.locked');
+  $locked['forum'] = 'forum';
+  Drupal::state()->set('node.type.locked', $locked);
 }
 
 /**
@@ -106,11 +105,6 @@ function forum_enable() {
       ))
       ->save();
   }
-
-  // Ensure the forum node type is available.
-  node_types_rebuild();
-  $types = node_type_get_types();
-  node_add_body_field($types['forum']);
 }
 
 /**
@@ -120,8 +114,6 @@ function forum_uninstall() {
   // Load the dependent Taxonomy module, in case it has been disabled.
   drupal_load('module', 'taxonomy');
 
-  variable_del('node_options_forum');
-
   if ($field = field_info_field('taxonomy_forums')) {
     $field->delete();
   }
@@ -129,6 +121,10 @@ function forum_uninstall() {
   // Purge field data now to allow taxonomy module to be uninstalled
   // if this is the only field remaining.
   field_purge_batch(10);
+  // Allow to delete a forum's node type.
+  $locked = Drupal::state()->get('node.type.locked');
+  unset($locked['forum']);
+  Drupal::state()->set('node.type.locked', $locked);
 }
 
 /**
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index fedeb2d..11a1054 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -174,13 +174,13 @@ function forum_menu_local_tasks(&$data, $router_item, $root_path) {
       $links = array();
       // Loop through all bundles for forum taxonomy vocabulary field.
       $field = field_info_field('taxonomy_forums');
-      foreach ($field['bundles']['node'] as $type) {
-        if (node_access('create', $type)) {
-          $links[$type] = array(
+      foreach ($field['bundles']['node'] as $type_name) {
+        if (($type = entity_load('node_type', $type_name)) && node_access('create', $type_name)) {
+          $links[$type_name] = array(
             '#theme' => 'menu_local_action',
             '#link' => array(
-              'title' => t('Add new @node_type', array('@node_type' => node_type_get_label($type))),
-              'href' => 'node/add/' . $type . '/' . $forum_term->id(),
+              'title' => t('Add new @node_type', array('@node_type' => $type->label())),
+              'href' => 'node/add/' . $type_name . '/' . $forum_term->id(),
             ),
           );
         }
@@ -427,20 +427,6 @@ function forum_node_load($nodes) {
 }
 
 /**
- * Implements hook_node_info().
- */
-function forum_node_info() {
-  return array(
-    'forum' => array(
-      'name' => t('Forum topic'),
-      'base' => 'forum',
-      'description' => t('A <em>forum topic</em> starts a new discussion thread within a forum.'),
-      'title_label' => t('Subject'),
-    )
-  );
-}
-
-/**
  * Implements hook_permission().
  */
 function forum_permission() {
diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
index c28b1dc..9cd6ae9 100644
--- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
+++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
@@ -204,7 +204,7 @@ function testForum() {
 
     // Test loading multiple forum nodes on the front page.
     $this->drupalLogin($this->drupalCreateUser(array('administer content types', 'create forum content', 'post comments')));
-    $this->drupalPost('admin/structure/types/manage/forum', array('node_options[promote]' => 'promote'), t('Save content type'));
+    $this->drupalPost('admin/structure/types/manage/forum', array('settings[node][options][promote]' => 'promote'), t('Save content type'));
     $this->createForumTopic($this->forum, FALSE);
     $this->createForumTopic($this->forum, FALSE);
     $this->drupalGet('node');
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 6b45fa1..f18d494 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -5,6 +5,7 @@
  * Add language handling functionality to Drupal.
  */
 
+use Drupal\node\NodeTypeInterface;
 use Drupal\Core\Language\Language;
 
 /**
@@ -322,6 +323,18 @@ function language_configuration_element_process($element, &$form_state, &$form)
     ),
   );
 
+  // Do not add the submit callback for the language content settings page,
+  // which is handled separately.
+  if (array_search('language_content_settings_form_submit', $form['#submit']) === FALSE) {
+    // Determine where to attach the language_configuration element submit handler.
+    // @todo Form API: Allow form widgets/sections to declare #submit handlers.
+    if (isset($form['actions']['submit']['#submit']) && array_search('language_configuration_element_submit', $form['actions']['submit']['#submit']) === FALSE) {
+      $form['actions']['submit']['#submit'][] = 'language_configuration_element_submit';
+    }
+    elseif (array_search('language_configuration_element_submit', $form['#submit']) === FALSE) {
+      $form['#submit'][] = 'language_configuration_element_submit';
+    }
+  }
   return $element;
 }
 
@@ -412,10 +425,10 @@ function language_get_default_configuration_settings_key($entity_type, $bundle)
 /**
  * Implements hook_node_type_update().
  */
-function language_node_type_update($info) {
-  if (!empty($info->old_type) && $info->old_type != $info->type) {
-    language_save_default_configuration('node', $info->type, language_get_default_configuration('node', $info->old_type));
-    language_clear_default_configuration('node', $info->old_type);
+function language_node_type_update(NodeTypeInterface $type) {
+  if ($type->original->id() != $type->id()) {
+    language_save_default_configuration('node', $type->id(), language_get_default_configuration('node', $type->original->id()));
+    language_clear_default_configuration('node', $type->original->id());
   }
 }
 
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index 68c3125..f506445 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -670,7 +670,7 @@ function menu_node_submit(EntityInterface $node, $form, $form_state) {
  */
 function menu_form_node_type_form_alter(&$form, $form_state) {
   $menu_options = menu_get_menus();
-  $type = $form['#node_type'];
+  $type = $form_state['controller']->getEntity();
   $form['menu'] = array(
     '#type' => 'details',
     '#title' => t('Menu settings'),
@@ -683,7 +683,7 @@ function menu_form_node_type_form_alter(&$form, $form_state) {
   $form['menu']['menu_options'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Available menus'),
-    '#default_value' => variable_get('menu_options_' . $type->type, array('main')),
+    '#default_value' => variable_get('menu_options_' . $type->id(), array('main')),
     '#options' => $menu_options,
     '#description' => t('The menus available to place links in for this content type.'),
   );
@@ -696,7 +696,7 @@ function menu_form_node_type_form_alter(&$form, $form_state) {
   $form['menu']['menu_parent'] = array(
     '#type' => 'select',
     '#title' => t('Default parent item'),
-    '#default_value' => variable_get('menu_parent_' . $type->type, 'main:0'),
+    '#default_value' => variable_get('menu_parent_' . $type->id(), 'main:0'),
     '#options' => $options,
     '#description' => t('Choose the menu item to be the default parent for a new link in the content authoring form.'),
     '#attributes' => array('class' => array('menu-title-select')),
diff --git a/core/modules/node/content_types.inc b/core/modules/node/content_types.inc
deleted file mode 100644
index 156576b..0000000
--- a/core/modules/node/content_types.inc
+++ /dev/null
@@ -1,491 +0,0 @@
-<?php
-
-/**
- * @file
- * Content type editing user interface.
- */
-
-/**
- * Page callback: Displays the content type admin overview page.
- *
- * @return array
- *   An array as expected by drupal_render().
- *
- * @see node_menu()
- */
-function node_overview_types() {
-  $types = node_type_get_types();
-  $names = node_type_get_names();
-  $field_ui = module_exists('field_ui');
-  $header = array(t('Name'), t('Operations'));
-  $rows = array();
-
-  foreach ($names as $key => $name) {
-    $type = $types[$key];
-    $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type)));
-    if ($field_ui && user_access('administer node fields')) {
-      $links['fields'] = array(
-        'title' => t('Manage fields'),
-        'href' => 'admin/structure/types/manage/' . $type->type . '/fields',
-        'weight' => 0,
-      );
-    }
-    if ($field_ui && user_access('administer node display')) {
-      $links['display'] = array(
-        'title' => t('Manage display'),
-        'href' => 'admin/structure/types/manage/' . $type->type . '/display',
-        'weight' => 5,
-      );
-    }
-
-    $links['edit'] = array(
-      'title' => t('Edit'),
-      'href' => 'admin/structure/types/manage/' . $type->type,
-      'weight' => 10,
-    );
-
-    if ($type->custom) {
-      $links['delete'] = array(
-        'title' => t('Delete'),
-        'href' => 'admin/structure/types/manage/' . $type->type . '/delete',
-        'weight' => 15,
-      );
-    }
-
-    $row[] = array(
-      'data' => array(
-        '#type' => 'operations',
-        '#links' => $links,
-      ),
-    );
-
-    $rows[] = $row;
-  }
-
-  $build['node_table'] = array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $rows,
-    '#empty' => t('No content types available. <a href="@link">Add content type</a>.', array('@link' => url('admin/structure/types/add'))),
-  );
-
-  return $build;
-}
-
-/**
- * Returns HTML for a node type description for the content type admin page.
- *
- * @param $variables
- *   An associative array containing:
- *   - name: The human-readable name of the content type.
- *   - type: An object containing the 'type' (machine name) and 'description' of
- *     the content type.
- *
- * @return string
- *   An HTML-formatted string of the description for this node type.
- *
- * @ingroup themeable
- */
-function theme_node_admin_overview($variables) {
-  $name = $variables['name'];
-  $type = $variables['type'];
-
-  $output = check_plain($name);
-  $output .= ' <small>' . t('(Machine name: @type)', array('@type' => $type->type)) . '</small>';
-  $output .= '<div class="description">' . filter_xss_admin($type->description) . '</div>';
-  return $output;
-}
-
-/**
- * Form constructor for the node type editing form.
- *
- * @param $type
- *   (optional) An object representing the node type, when editing an existing
- *   node type.
- *
- * @see node_type_form_validate()
- * @see node_type_form_submit()
- * @ingroup forms
- */
-function node_type_form($form, &$form_state, $type = NULL) {
-  if (!isset($type->type)) {
-    // This is a new type. Node module managed types are custom and unlocked.
-    $type = node_type_set_defaults(array('custom' => 1, 'locked' => 0));
-  }
-
-  // Make the type object available to implementations of hook_form_alter.
-  $form['#node_type'] = $type;
-
-  $form['name'] = array(
-    '#title' => t('Name'),
-    '#type' => 'textfield',
-    '#default_value' => $type->name,
-    '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'),
-    '#required' => TRUE,
-    '#size' => 30,
-  );
-
-  $form['type'] = array(
-    '#type' => 'machine_name',
-    '#default_value' => $type->type,
-    '#maxlength' => 32,
-    '#disabled' => $type->locked,
-    '#machine_name' => array(
-      'exists' => 'node_type_load',
-      'source' => array('name'),
-    ),
-    '#description' => t('A unique machine-readable name for this content type. It must only contain lowercase letters, numbers, and underscores. This name will be used for constructing the URL of the %node-add page, in which underscores will be converted into hyphens.', array(
-      '%node-add' => t('Add new content'),
-    )),
-  );
-
-  $form['description'] = array(
-    '#title' => t('Description'),
-    '#type' => 'textarea',
-    '#default_value' => $type->description,
-    '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content</em> page.'),
-  );
-
-  $form['additional_settings'] = array(
-    '#type' => 'vertical_tabs',
-    '#attached' => array(
-      'library' => array(array('node', 'drupal.content_types')),
-    ),
-  );
-
-  $form['submission'] = array(
-    '#type' => 'details',
-    '#title' => t('Submission form settings'),
-    '#group' => 'additional_settings',
-  );
-  $form['submission']['title_label'] = array(
-    '#title' => t('Title field label'),
-    '#type' => 'textfield',
-    '#default_value' => $type->title_label,
-    '#required' => TRUE,
-  );
-  if (!$type->has_title) {
-    // Avoid overwriting a content type that intentionally does not have a
-    // title field.
-    $form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
-    $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
-    $form['submission']['title_label']['#required'] = FALSE;
-  }
-  $form['submission']['node_preview'] = array(
-    '#type' => 'radios',
-    '#title' => t('Preview before submitting'),
-    '#default_value' => variable_get('node_preview_' . $type->type, DRUPAL_OPTIONAL),
-    '#options' => array(
-      DRUPAL_DISABLED => t('Disabled'),
-      DRUPAL_OPTIONAL => t('Optional'),
-      DRUPAL_REQUIRED => t('Required'),
-    ),
-  );
-  $form['submission']['help']  = array(
-    '#type' => 'textarea',
-    '#title' => t('Explanation or submission guidelines'),
-    '#default_value' => $type->help,
-    '#description' => t('This text will be displayed at the top of the page when creating or editing content of this type.'),
-  );
-  $form['workflow'] = array(
-    '#type' => 'details',
-    '#title' => t('Publishing options'),
-    '#collapsed' => TRUE,
-    '#group' => 'additional_settings',
-  );
-  $form['workflow']['node_options'] = array('#type' => 'checkboxes',
-    '#title' => t('Default options'),
-    '#default_value' => variable_get('node_options_' . $type->type, array('status', 'promote')),
-    '#options' => array(
-      'status' => t('Published'),
-      'promote' => t('Promoted to front page'),
-      'sticky' => t('Sticky at top of lists'),
-      'revision' => t('Create new revision'),
-    ),
-    '#description' => t('Users with the <em>Administer content</em> permission will be able to override these options.'),
-  );
-  if (module_exists('language')) {
-    $form['language'] = array(
-      '#type' => 'details',
-      '#title' => t('Language settings'),
-      '#collapsed' => TRUE,
-      '#group' => 'additional_settings',
-    );
-
-    $language_configuration = language_get_default_configuration('node', $type->type);
-    $form['language']['language_configuration'] = array(
-      '#type' => 'language_configuration',
-      '#entity_information' => array(
-        'entity_type' => 'node',
-        'bundle' => $type->type,
-      ),
-      '#default_value' => $language_configuration,
-    );
-
-    $form['#submit'][] = 'language_configuration_element_submit';
-  }
-  $form['display'] = array(
-    '#type' => 'details',
-    '#title' => t('Display settings'),
-    '#collapsed' => TRUE,
-    '#group' => 'additional_settings',
-  );
-  $form['display']['node_submitted'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Display author and date information.'),
-    '#default_value' => variable_get('node_submitted_' . $type->type, TRUE),
-    '#description' => t('Author username and publish date will be displayed.'),
-  );
-  $form['old_type'] = array(
-    '#type' => 'value',
-    '#value' => $type->type,
-  );
-  $form['orig_type'] = array(
-    '#type' => 'value',
-    '#value' => isset($type->orig_type) ? $type->orig_type : '',
-  );
-  $form['base'] = array(
-    '#type' => 'value',
-    '#value' => $type->base,
-  );
-  $form['custom'] = array(
-    '#type' => 'value',
-    '#value' => $type->custom,
-  );
-  $form['modified'] = array(
-    '#type' => 'value',
-    '#value' => $type->modified,
-  );
-  $form['locked'] = array(
-    '#type' => 'value',
-    '#value' => $type->locked,
-  );
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save content type'),
-    '#weight' => 40,
-  );
-
-  if ($type->custom) {
-    if (!empty($type->type)) {
-      $form['actions']['delete'] = array(
-        '#type' => 'submit',
-        '#value' => t('Delete content type'),
-        '#weight' => 45,
-      );
-    }
-  }
-  $form['#submit'][] = 'node_type_form_submit';
-
-  return $form;
-}
-
-/**
- * Helper function for teaser length choices.
- *
- * @param int $length
- *   An integer representing the desired length of the teaser string.
- *
- * @return string
- *   A string that reprents the teaser length options.
- */
-function _node_characters($length) {
-  return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
-}
-
-/**
- * Form validation handler for node_type_form().
- *
- * @see node_type_form_submit()
- */
-function node_type_form_validate($form, &$form_state) {
-  $type = new stdClass();
-  $type->type = $form_state['values']['type'];
-  $type->name = trim($form_state['values']['name']);
-
-  // Work out what the type was before the user submitted this form
-  $old_type = $form_state['values']['old_type'];
-
-  $types = node_type_get_names();
-
-  if (!$form_state['values']['locked']) {
-    // 'theme' conflicts with theme_node_form().
-    // '0' is invalid, since elsewhere we check it using empty().
-    if (in_array($type->type, array('0', 'theme'))) {
-      form_set_error('type', t("Invalid machine-readable name. Enter a name other than %invalid.", array('%invalid' => $type->type)));
-    }
-  }
-
-  $names = array_flip($types);
-
-  if (isset($names[$type->name]) && $names[$type->name] != $old_type) {
-    form_set_error('name', t('The human-readable name %name is already taken.', array('%name' => $type->name)));
-  }
-}
-
-/**
- * Form submission handler for node_type_form().
- *
- * @see node_type_form_validate()
- */
-function node_type_form_submit($form, &$form_state) {
-  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
-
-  $type = node_type_set_defaults();
-
-  $type->type = $form_state['values']['type'];
-  $type->name = trim($form_state['values']['name']);
-  $type->orig_type = trim($form_state['values']['orig_type']);
-  $type->old_type = isset($form_state['values']['old_type']) ? $form_state['values']['old_type'] : $type->type;
-
-  $type->description = $form_state['values']['description'];
-  $type->help = $form_state['values']['help'];
-  $type->title_label = $form_state['values']['title_label'];
-  // title_label is required in core; has_title will always be true, unless a
-  // module alters the title field.
-  $type->has_title = ($type->title_label != '');
-
-  $type->base = !empty($form_state['values']['base']) ? $form_state['values']['base'] : 'node_content';
-  $type->custom = $form_state['values']['custom'];
-  $type->modified = TRUE;
-  $type->locked = $form_state['values']['locked'];
-  if (isset($form['#node_type']->module)) {
-    $type->module = $form['#node_type']->module;
-  }
-
-  if ($op == t('Delete content type')) {
-    $form_state['redirect'] = 'admin/structure/types/manage/' . $type->old_type . '/delete';
-    return;
-  }
-
-  $variables = $form_state['values'];
-
-  // Remove everything that's been saved already - whatever's left is assumed
-  // to be a persistent variable.
-  foreach ($variables as $key => $value) {
-    if (isset($type->$key)) {
-      unset($variables[$key]);
-    }
-  }
-
-  unset($variables['form_token'], $variables['op'], $variables['submit'], $variables['delete'], $variables['reset'], $variables['form_id'], $variables['form_build_id']);
-
-  // Save or reset persistent variable values.
-  foreach ($variables as $key => $value) {
-    $variable_new = $key . '_' . $type->type;
-    $variable_old = $key . '_' . $type->old_type;
-
-    if (is_array($value)) {
-      $value = array_keys(array_filter($value));
-    }
-    variable_set($variable_new, $value);
-
-    if ($variable_new != $variable_old) {
-      variable_del($variable_old);
-    }
-  }
-
-  // Saving the content type after saving the variables allows modules to act
-  // on those variables via hook_node_type_insert().
-  $status = node_type_save($type);
-
-  node_types_rebuild();
-  menu_router_rebuild();
-  $t_args = array('%name' => $type->name);
-
-  if ($status == SAVED_UPDATED) {
-    drupal_set_message(t('The content type %name has been updated.', $t_args));
-  }
-  elseif ($status == SAVED_NEW) {
-    node_add_body_field($type);
-    drupal_set_message(t('The content type %name has been added.', $t_args));
-    watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE, l(t('view'), 'admin/structure/types'));
-  }
-
-  $form_state['redirect'] = 'admin/structure/types';
-  return;
-}
-
-/**
- * Implements hook_node_type_update().
- */
-function node_node_type_update($info) {
-  if (!empty($info->old_type) && $info->old_type != $info->type) {
-    $update_count = node_type_update_nodes($info->old_type, $info->type);
-
-    if ($update_count) {
-      drupal_set_message(format_plural($update_count, 'Changed the content type of 1 post from %old-type to %type.', 'Changed the content type of @count posts from %old-type to %type.', array('%old-type' => $info->old_type, '%type' => $info->type)));
-    }
-  }
-}
-
-/**
- * Resets relevant fields of a module-defined node type to their default values.
- *
- * @param $type
- *   The node type to reset. The node type is passed back by reference with its
- *   resetted values. If there is no module-defined info for this node type,
- *   then nothing happens.
- */
-function node_type_reset($type) {
-  $info_array = module_invoke_all('node_info');
-  if (isset($info_array[$type->orig_type])) {
-    $info_array[$type->orig_type]['type'] = $type->orig_type;
-    $info = node_type_set_defaults($info_array[$type->orig_type]);
-
-    foreach ($info as $field => $value) {
-      $type->$field = $value;
-    }
-  }
-}
-
-/**
- * Page callback: Form constructor for the content type delete form.
- *
- * @param $type
- *   Content type object.
- *
- * @return
- *   Form array for delete confirmation form.
- *
- * @see node_type_delete_confirm_submit()
- * @ingroup forms
- */
-function node_type_delete_confirm($form, &$form_state, $type) {
-  $form['type'] = array('#type' => 'value', '#value' => $type->type);
-  $form['name'] = array('#type' => 'value', '#value' => $type->name);
-
-  $message = t('Are you sure you want to delete the content type %type?', array('%type' => $type->name));
-
-  $num_nodes = db_query("SELECT COUNT(*) FROM {node} WHERE type = :type", array(':type' => $type->type))->fetchField();
-  if ($num_nodes) {
-    drupal_set_title($message, PASS_THROUGH);
-    $caption = '<p>' . format_plural($num_nodes, '%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', '%type is used by @count pieces of content on your site. You may not remove %type until you have removed all of the %type content.', array('%type' => $type->name)) . '</p>';
-    $form['description'] = array('#markup' => $caption);
-    return $form;
-  }
-
-  $caption = '<p>' . t('This action cannot be undone.') . '</p>';
-
-  return confirm_form($form, $message, 'admin/structure/types', $caption, t('Delete'));
-}
-
-/**
- * Form submission handler for node_type_delete_confirm().
- */
-function node_type_delete_confirm_submit($form, &$form_state) {
-  node_type_delete($form_state['values']['type']);
-
-  variable_del('node_preview_' . $form_state['values']['type']);
-  $t_args = array('%name' => $form_state['values']['name']);
-  drupal_set_message(t('The content type %name has been deleted.', $t_args));
-  watchdog('node', 'Deleted content type %name.', $t_args, WATCHDOG_NOTICE);
-
-  node_types_rebuild();
-  menu_router_rebuild();
-
-  $form_state['redirect'] = 'admin/structure/types';
-  return;
-}
diff --git a/core/modules/node/content_types.js b/core/modules/node/content_types.js
index 40d6422..f6a545b 100644
--- a/core/modules/node/content_types.js
+++ b/core/modules/node/content_types.js
@@ -18,10 +18,10 @@ Drupal.behaviors.contentTypes = {
     });
     $context.find('#edit-workflow').drupalSetSummary(function(context) {
       var vals = [];
-      $(context).find("input[name^='node_options']:checked").parent().each(function() {
+      $(context).find("input[name^='settings[node][options']:checked").parent().each(function() {
         vals.push(Drupal.checkPlain($(this).text()));
       });
-      if (!$(context).find('#edit-node-options-status').is(':checked')) {
+      if (!$(context).find('#edit-settings-node-options-status').is(':checked')) {
         vals.unshift(Drupal.t('Not published'));
       }
       return vals.join(', ');
@@ -43,7 +43,7 @@ Drupal.behaviors.contentTypes = {
       $context.find('input:checked').next('label').each(function() {
         vals.push(Drupal.checkPlain($(this).text()));
       });
-      if (!$context.find('#edit-node-submitted').is(':checked')) {
+      if (!$context.find('#edit-settings-node-submitted').is(':checked')) {
         vals.unshift(Drupal.t("Don't display post information"));
       }
       return vals.join(', ');
diff --git a/core/modules/node/lib/Drupal/node/Form/NodeTypeDeleteConfirm.php b/core/modules/node/lib/Drupal/node/Form/NodeTypeDeleteConfirm.php
new file mode 100644
index 0000000..23973c9
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Form/NodeTypeDeleteConfirm.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Form\NodeTypeDeleteConfirm.
+ */
+
+namespace Drupal\node\Form;
+
+use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityControllerInterface;
+use Drupal\Core\Database\Connection;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Provides a form for content type deletion.
+ */
+class NodeTypeDeleteConfirm extends EntityConfirmFormBase implements EntityControllerInterface {
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * Constructs a new NodeTypeDeleteConfirm object.
+   *
+   * @param \Drupal\Core\Database\Connection $database
+   *   The database connection.
+   */
+  public function __construct(Connection $database) {
+    $this->database = $database;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $container->get('database')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return t('Are you sure you want to delete the content type %type?', array('%type' => $this->entity->label()));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelPath() {
+    return 'admin/structure/types';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return t('Delete');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state, Request $request = NULL) {
+    $num_nodes = $this->database->query("SELECT COUNT(*) FROM {node} WHERE type = :type", array(':type' => $this->entity->id()))->fetchField();
+    if ($num_nodes) {
+      drupal_set_title($this->getQuestion(), PASS_THROUGH);
+      $caption = '<p>' . format_plural($num_nodes, '%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', '%type is used by @count pieces of content on your site. You may not remove %type until you have removed all of the %type content.', array('%type' => $this->entity->label())) . '</p>';
+      $form['description'] = array('#markup' => $caption);
+      return $form;
+    }
+
+    return parent::buildForm($form, $form_state, $request);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submit(array $form, array &$form_state) {
+    $this->entity->delete();
+    $t_args = array('%name' => $this->entity->label());
+    drupal_set_message(t('The content type %name has been deleted.', $t_args));
+    watchdog('node', 'Deleted content type %name.', $t_args, WATCHDOG_NOTICE);
+
+    $form_state['redirect'] = $this->getCancelPath();
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index e64db93..2c362b6 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -18,6 +18,13 @@
 class NodeFormController extends EntityFormController {
 
   /**
+   * Default settings for this content/node type.
+   *
+   * @var array
+   */
+  protected $settings;
+
+  /**
    * Prepares the node object.
    *
    * Fills in a few default values, and then invokes hook_node_prepare() on all
@@ -28,13 +35,20 @@ class NodeFormController extends EntityFormController {
   protected function prepareEntity() {
     $node = $this->entity;
     // Set up default values, if required.
-    $node_options = variable_get('node_options_' . $node->type, array('status', 'promote'));
+    $type = entity_load('node_type', $node->bundle());
+    $this->settings = $type->getModuleSettings('node');
+    $this->settings += array(
+      'options' => array('status', 'promote'),
+      'preview' => DRUPAL_OPTIONAL,
+      'submitted' => TRUE,
+    );
+
     // If this is a new node, fill in the default values.
     if (!isset($node->nid) || isset($node->is_new)) {
       foreach (array('status', 'promote', 'sticky') as $key) {
         // Multistep node forms might have filled in something already.
         if (!isset($node->$key)) {
-          $node->$key = (int) in_array($key, $node_options);
+          $node->$key = (int) in_array($key, $this->settings['options']);
         }
       }
       global $user;
@@ -47,7 +61,7 @@ protected function prepareEntity() {
       $node->log = NULL;
     }
     // Always use the default revision setting.
-    $node->setNewRevision(in_array('revision', $node_options));
+    $node->setNewRevision(in_array('revision', $this->settings['options']));
 
     module_invoke_all('node_prepare', $node);
   }
@@ -240,7 +254,7 @@ public function form(array $form, array &$form_state) {
   protected function actions(array $form, array &$form_state) {
     $element = parent::actions($form, $form_state);
     $node = $this->entity;
-    $preview_mode = variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL);
+    $preview_mode = $this->settings['preview'];
 
     $element['submit']['#access'] = $preview_mode != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview']));
 
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeAccessController.php b/core/modules/node/lib/Drupal/node/NodeTypeAccessController.php
new file mode 100644
index 0000000..40327e3
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeTypeAccessController.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\taxonomy\NodeTypeAccessController.
+ */
+
+namespace Drupal\node;
+
+use Drupal\Core\Entity\EntityAccessController;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Defines an access controller for the node type entity.
+ *
+ * @see \Drupal\node\Plugin\Core\Entity\NodeType.
+ */
+class NodeTypeAccessController extends EntityAccessController {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
+    if ($operation == 'delete' && $entity->isLocked()) {
+      return FALSE;
+    }
+    return user_access('administer content types', $account);
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeFormController.php b/core/modules/node/lib/Drupal/node/NodeTypeFormController.php
new file mode 100644
index 0000000..aaa287b
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeTypeFormController.php
@@ -0,0 +1,280 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\NodeTypeFormController.
+ */
+
+namespace Drupal\node;
+
+use Drupal\Core\Entity\EntityFormController;
+use Drupal\Core\Entity\EntityControllerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+/**
+ * Form controller for node type forms.
+ */
+class NodeTypeFormController extends EntityFormController implements EntityControllerInterface {
+
+  /**
+   * The module handler service.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a NodeTypeFormController object.
+   *
+   * @param string $operation
+   *   The name of the current operation.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke hooks on.
+   */
+  public function __construct($operation, ModuleHandlerInterface $module_handler) {
+    parent::__construct($operation);
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info, $operation = NULL) {
+    return new static(
+      $operation,
+      $container->get('module_handler')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, array &$form_state) {
+    $form = parent::form($form, $form_state);
+
+    $type = $this->entity;
+    if ($this->operation == 'add') {
+      drupal_set_title(t('Add content type'));
+    }
+    elseif ($this->operation == 'edit') {
+      drupal_set_title(t('Edit %label content type', array('%label' => $type->label())), PASS_THROUGH);
+    }
+
+    $node_settings = $type->getModuleSettings('node');
+    // Ensure default settings.
+    $node_settings += array(
+      'options' => array('status', 'promote'),
+      'preview' => DRUPAL_OPTIONAL,
+      'submitted' => TRUE,
+    );
+
+    $form['name'] = array(
+      '#title' => t('Name'),
+      '#type' => 'textfield',
+      '#default_value' => $type->name,
+      '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'),
+      '#required' => TRUE,
+      '#size' => 30,
+    );
+
+    $form['type'] = array(
+      '#type' => 'machine_name',
+      '#default_value' => $type->id(),
+      '#maxlength' => 32,
+      '#disabled' => $type->isLocked(),
+      '#machine_name' => array(
+        'exists' => 'node_type_load',
+        'source' => array('name'),
+      ),
+      '#description' => t('A unique machine-readable name for this content type. It must only contain lowercase letters, numbers, and underscores. This name will be used for constructing the URL of the %node-add page, in which underscores will be converted into hyphens.', array(
+        '%node-add' => t('Add new content'),
+      )),
+    );
+
+    $form['description'] = array(
+      '#title' => t('Description'),
+      '#type' => 'textarea',
+      '#default_value' => $type->description,
+      '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content</em> page.'),
+    );
+
+    $form['additional_settings'] = array(
+      '#type' => 'vertical_tabs',
+      '#attached' => array(
+        'library' => array(array('node', 'drupal.content_types')),
+      ),
+    );
+
+    $form['submission'] = array(
+      '#type' => 'details',
+      '#title' => t('Submission form settings'),
+      '#group' => 'additional_settings',
+    );
+    $form['submission']['title_label'] = array(
+      '#title' => t('Title field label'),
+      '#type' => 'textfield',
+      '#default_value' => $type->title_label,
+      '#required' => TRUE,
+    );
+    if (!$type->has_title) {
+      // Avoid overwriting a content type that intentionally does not have a
+      // title field.
+      $form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
+      $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
+      $form['submission']['title_label']['#required'] = FALSE;
+    }
+    $form['submission']['preview'] = array(
+      '#type' => 'radios',
+      '#title' => t('Preview before submitting'),
+      '#parents' => array('settings', 'node', 'preview'),
+      '#default_value' => $node_settings['preview'],
+      '#options' => array(
+        DRUPAL_DISABLED => t('Disabled'),
+        DRUPAL_OPTIONAL => t('Optional'),
+        DRUPAL_REQUIRED => t('Required'),
+      ),
+    );
+    $form['submission']['help']  = array(
+      '#type' => 'textarea',
+      '#title' => t('Explanation or submission guidelines'),
+      '#default_value' => $type->help,
+      '#description' => t('This text will be displayed at the top of the page when creating or editing content of this type.'),
+    );
+    $form['workflow'] = array(
+      '#type' => 'details',
+      '#title' => t('Publishing options'),
+      '#collapsed' => TRUE,
+      '#group' => 'additional_settings',
+    );
+    $form['workflow']['options'] = array('#type' => 'checkboxes',
+      '#title' => t('Default options'),
+      '#parents' => array('settings', 'node', 'options'),
+      '#default_value' => $node_settings['options'],
+      '#options' => array(
+        'status' => t('Published'),
+        'promote' => t('Promoted to front page'),
+        'sticky' => t('Sticky at top of lists'),
+        'revision' => t('Create new revision'),
+      ),
+      '#description' => t('Users with the <em>Administer content</em> permission will be able to override these options.'),
+    );
+    if ($this->moduleHandler->moduleExists('language')) {
+      $form['language'] = array(
+        '#type' => 'details',
+        '#title' => t('Language settings'),
+        '#collapsed' => TRUE,
+        '#group' => 'additional_settings',
+      );
+
+      $language_configuration = language_get_default_configuration('node', $type->id());
+      $form['language']['language_configuration'] = array(
+        '#type' => 'language_configuration',
+        '#entity_information' => array(
+          'entity_type' => 'node',
+          'bundle' => $type->id(),
+        ),
+        '#default_value' => $language_configuration,
+      );
+    }
+    $form['display'] = array(
+      '#type' => 'details',
+      '#title' => t('Display settings'),
+      '#collapsed' => TRUE,
+      '#group' => 'additional_settings',
+    );
+    $form['display']['submitted'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Display author and date information.'),
+      '#parents' => array('settings', 'node', 'submitted'),
+      '#default_value' => $node_settings['submitted'],
+      '#description' => t('Author username and publish date will be displayed.'),
+    );
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function actions(array $form, array &$form_state) {
+    $actions = parent::actions($form, $form_state);
+    $actions['submit']['#value'] = t('Save content type');
+    $actions['delete']['#value'] = t('Delete content type');
+    $actions['delete']['#access'] = $this->entity->access('delete');
+    return $actions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+
+    $id = trim($form_state['values']['type']);
+    // '0' is invalid, since elsewhere we check it using empty().
+    if ($id == '0') {
+      form_set_error('type', t("Invalid machine-readable name. Enter a name other than %invalid.", array('%invalid' => $id)));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, array &$form_state) {
+    $type = $this->entity;
+    $type->type = trim($type->id());
+    $type->name = trim($type->name);
+
+    // title_label is required in core; has_title will always be TRUE, unless a
+    // module alters the title field.
+    $type->has_title = ($type->title_label != '');
+
+    $variables = $form_state['values'];
+
+    // Do not save settings from vertical tabs.
+    // @todo Fix vertical_tabs.
+    unset($variables['additional_settings__active_tab']);
+
+    // @todo Remove the entire following code after converting node settings of
+    //   Comment and Menu module. https://drupal.org/node/2026165
+    // Remove all node type entity properties.
+    foreach (get_class_vars(get_class($type)) as $key => $value) {
+      unset($variables[$key]);
+    }
+    // Save or reset persistent variable values.
+    foreach ($variables as $key => $value) {
+      $variable_new = $key . '_' . $type->id();
+      $variable_old = $key . '_' . $type->getOriginalID();
+      if (is_array($value)) {
+        $value = array_keys(array_filter($value));
+      }
+      variable_set($variable_new, $value);
+      if ($variable_new != $variable_old) {
+        variable_del($variable_old);
+      }
+    }
+    // Saving the content type after saving the variables allows modules to act
+    // on those variables via hook_node_type_insert().
+    $status = $type->save();
+
+    $t_args = array('%name' => $type->label());
+
+    if ($status == SAVED_UPDATED) {
+      drupal_set_message(t('The content type %name has been updated.', $t_args));
+    }
+    elseif ($status == SAVED_NEW) {
+      drupal_set_message(t('The content type %name has been added.', $t_args));
+      watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE, l(t('view'), 'admin/structure/types'));
+    }
+
+    $form_state['redirect'] = 'admin/structure/types';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete(array $form, array &$form_state) {
+    $form_state['redirect'] = 'admin/structure/types/manage/' . $this->entity->id() . '/delete';
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeInterface.php b/core/modules/node/lib/Drupal/node/NodeTypeInterface.php
new file mode 100644
index 0000000..691713b
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeTypeInterface.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\NodeTypeInterface.
+ */
+
+namespace Drupal\node;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface defining a node type entity.
+ */
+interface NodeTypeInterface extends ConfigEntityInterface {
+
+  /**
+   * Returns the configured node type settings of a given module, if any.
+   *
+   * @param string $module
+   *   The name of the module whose settings to return.
+   *
+   * @return array
+   *   An associative array containing the module's settings for the node type.
+   *   Note that this can be empty, and default values do not necessarily exist.
+   */
+  public function getModuleSettings($module);
+
+  /**
+   * Returns a locked state of the type.
+   *
+   * @return string|false
+   *   The module name that locks the type or FALSE.
+   */
+  public function isLocked();
+
+}
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeListController.php b/core/modules/node/lib/Drupal/node/NodeTypeListController.php
new file mode 100644
index 0000000..3f51613
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeTypeListController.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * Contains \Drupal\node\NodeTypeListController.
+ */
+
+namespace Drupal\node;
+
+use Drupal\Core\Config\Entity\ConfigEntityListController;
+use Drupal\Core\Entity\EntityControllerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Routing\PathBasedGeneratorInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Component\Utility\Xss;
+use Drupal\Component\Utility\String;
+
+/**
+ * Provides a listing of node types.
+ */
+class NodeTypeListController extends ConfigEntityListController implements EntityControllerInterface {
+
+  /**
+   * The url generator service.
+   *
+   * @var \Drupal\Core\Routing\PathBasedGeneratorInterface
+   */
+  protected $urlGenerator;
+
+  /**
+   * Constructs a NodeTypeFormController object.
+   *
+   * @param string $entity_type
+   *   The type of entity to be listed.
+   * @param array $entity_info
+   *   An array of entity info for the entity type.
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
+   *   The entity storage controller class.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke hooks on.
+   * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator
+   *   The url generator service.
+   */
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, PathBasedGeneratorInterface $url_generator) {
+    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+    $this->urlGenerator = $url_generator;
+  }
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $entity_type,
+      $entity_info,
+      $container->get('plugin.manager.entity')->getStorageController($entity_type),
+      $container->get('module_handler'),
+      $container->get('url_generator')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader() {
+    $row['title'] = t('Name');
+    $row['description'] = array(
+      'data' => t('Description'),
+      'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
+    );
+    $row['operations'] = t('Operations');
+    return $row;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $entity) {
+    $row['title'] = array(
+      'data' => String::checkPlain($entity->label()),
+      'class' => array('menu-label'),
+    );
+    $row['description'] = Xss::filterAdmin($entity->description);
+    $row['operations']['data'] = $this->buildOperations($entity);
+    return $row;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOperations(EntityInterface $entity) {
+    $operations = parent::getOperations($entity);
+    if ($this->moduleHandler->moduleExists('field_ui') && user_access('administer node fields')) {
+      $uri = $entity->uri();
+      $operations['manage-fields'] = array(
+        'title' => t('Manage fields'),
+        'href' => $uri['path'] . '/fields',
+        'options' => $uri['options'],
+        'weight' => 0,
+      );
+      $operations['manage-display'] = array(
+        'title' => t('Manage display'),
+        'href' => $uri['path'] . '/display',
+        'options' => $uri['options'],
+        'weight' => 5,
+      );
+    }
+    if ($entity->isLocked()) {
+      unset($operations['delete']);
+    }
+    return $operations;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render() {
+    $build = parent::render();
+    $build['#empty'] = t('No content types available. <a href="@link">Add content type</a>.', array(
+      '@link' => $this->urlGenerator->generateFromPath('admin/structure/types/add'),
+    ));
+    return $build;
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/NodeType.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/NodeType.php
new file mode 100644
index 0000000..464fbe0
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/NodeType.php
@@ -0,0 +1,218 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Plugin\Core\Entity\NodeType.
+ */
+
+namespace Drupal\node\Plugin\Core\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\node\NodeTypeInterface;
+use Drupal\Core\Entity\Annotation\EntityType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the Node type configuration entity.
+ *
+ * @EntityType(
+ *   id = "node_type",
+ *   label = @Translation("Content type"),
+ *   module = "node",
+ *   controllers = {
+ *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *     "access" = "Drupal\node\NodeTypeAccessController",
+ *     "form" = {
+ *       "add" = "Drupal\node\NodeTypeFormController",
+ *       "edit" = "Drupal\node\NodeTypeFormController",
+ *       "delete" = "Drupal\node\Form\NodeTypeDeleteConfirm"
+ *     },
+ *     "list" = "Drupal\node\NodeTypeListController",
+ *   },
+ *   config_prefix = "node.type",
+ *   entity_keys = {
+ *     "id" = "type",
+ *     "label" = "name",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class NodeType extends ConfigEntityBase implements NodeTypeInterface {
+
+  /**
+   * The machine name of this node type.
+   *
+   * @var string
+   *
+   * @todo Rename to $id.
+   */
+  public $type;
+
+  /**
+   * The UUID of the node type.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The human-readable name of the node type.
+   *
+   * @var string
+   *
+   * @todo Rename to $label.
+   */
+  public $name;
+
+  /**
+   * A brief description of this node type.
+   *
+   * @var string
+   */
+  public $description;
+
+  /**
+   * Help information shown to the user when creating a Node of this type.
+   *
+   * @var string
+   */
+  public $help;
+
+  /**
+   * Indicates whether the Node entity of this type has a title.
+   *
+   * @var bool
+   *
+   * @todo Rename to $node_has_title.
+   */
+  public $has_title = TRUE;
+
+  /**
+   * The label to use for the title of a Node of this type in the user interface.
+   *
+   * @var string
+   *
+   * @todo Rename to $node_title_label.
+   */
+  public $title_label = 'Title';
+
+  /**
+   * Indicates whether a Body field should be created for this node type.
+   *
+   * This property affects entity creation only. It allows default configuration
+   * of modules and installation profiles to specify whether a Body field should
+   * be created for this bundle.
+   *
+   * @var bool
+   *
+   * @see \Drupal\node\Plugin\Core\Entity\NodeType::$create_body_label
+   */
+  protected $create_body = TRUE;
+
+  /**
+   * The label to use for the Body field upon entity creation.
+   *
+   * @see \Drupal\node\Plugin\Core\Entity\NodeType::$create_body
+   *
+   * @var string
+   */
+  protected $create_body_label = 'Body';
+
+  /**
+   * Module-specific settings for this node type, keyed by module name.
+   *
+   * @var array
+   *
+   * @todo Pluginify.
+   */
+  public $settings = array();
+
+  /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    return $this->type;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uri() {
+    return array(
+      'path' => 'admin/structure/types/manage/' . $this->id(),
+      'options' => array(
+        'entity_type' => $this->entityType,
+        'entity' => $this,
+      ),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getModuleSettings($module) {
+    if (isset($this->settings[$module]) && is_array($this->settings[$module])) {
+      return $this->settings[$module];
+    }
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isLocked() {
+    $locked = \Drupal::state()->get('node.type.locked');
+    return isset($locked[$this->id()]) ? $locked[$this->id()] : FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
+    if (!$update) {
+      // Clear the node type cache, so the new type appears.
+      \Drupal::cache()->deleteTags(array('node_types' => TRUE));
+
+      entity_invoke_bundle_hook('create', 'node', $this->id());
+
+      // Unless disabled, automatically create a Body field for new node types.
+      if ($this->get('create_body')) {
+        $label = $this->get('create_body_label');
+        node_add_body_field($this, $label);
+      }
+    }
+    elseif ($this->getOriginalID() != $this->id()) {
+      // Clear the node type cache to reflect the rename.
+      \Drupal::cache()->deleteTags(array('node_types' => TRUE));
+
+      $update_count = node_type_update_nodes($this->getOriginalID(), $this->id());
+      if ($update_count) {
+        drupal_set_message(format_plural($update_count,
+          'Changed the content type of 1 post from %old-type to %type.',
+          'Changed the content type of @count posts from %old-type to %type.',
+          array(
+            '%old-type' => $this->getOriginalID(),
+            '%type' => $this->id(),
+          )));
+      }
+      entity_invoke_bundle_hook('rename', 'node', $this->getOriginalID(), $this->id());
+    }
+    else {
+      // Invalidate the cache tag of the updated node type only.
+      cache()->invalidateTags(array('node_type' => $this->id()));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
+    // Clear the node type cache to reflect the removal.
+    $storage_controller->resetCache(array_keys($entities));
+    foreach ($entities as $entity) {
+      entity_invoke_bundle_hook('delete', 'node', $entity->id());
+    }
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php b/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php
index 9d93846..d06040a 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php
@@ -33,11 +33,9 @@ function title() {
     return $this->node_type($this->argument);
   }
 
-  function node_type($type) {
-    $output = node_type_get_label($type);
-    if (empty($output)) {
-      $output = t('Unknown content type');
-    }
+  function node_type($type_name) {
+    $type = entity_load('node_type', $type_name);
+    $output = $type ? $type->label() : t('Unknown content type');
     return check_plain($output);
   }
 
diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php b/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php
index 5a6c25f..6d31ae4 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php
@@ -45,7 +45,8 @@ public function buildOptionsForm(&$form, &$form_state) {
     */
   function render_name($data, $values) {
     if ($this->options['machine_name'] != 1 && $data !== NULL && $data !== '') {
-      return t($this->sanitizeValue(node_type_get_label($data)));
+      $type = entity_load('node_type', $data);
+      return $type ? t($this->sanitizeValue($type->label())) : '';
     }
     return $this->sanitizeValue($data);
   }
diff --git a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
index c5856e5..31d515f 100644
--- a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
@@ -26,7 +26,6 @@ public static function getInfo() {
 
   protected function setUp() {
     parent::setUp();
-    $this->installSchema('node', 'node_type');
     $this->installSchema('node', 'node');
     $this->installSchema('node', 'node_field_data');
     $this->installSchema('node', 'node_field_revision');
diff --git a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportChangeTest.php b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportChangeTest.php
new file mode 100644
index 0000000..8f162e0
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportChangeTest.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Tests\Config\NodeImportChangeTest.
+ */
+
+namespace Drupal\node\Tests\Config;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Tests updating content types as part of config import.
+ */
+class NodeImportChangeTest extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node', 'entity', 'field', 'text', 'field_sql_storage', 'system', 'node_test_config');
+
+  /**
+   * Set the default field storage backend for fields created during tests.
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', array('config_snapshot'));
+
+    // Set default storage backend.
+    $this->installConfig(array('field', 'node_test_config'));
+  }
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node config change tests',
+      'description' => 'Change content types during config create method invocation.',
+      'group' => 'Node',
+    );
+  }
+
+  /**
+   * Tests importing an updated content type.
+   */
+  public function testImportChange() {
+    $node_type_id = 'default';
+    $node_type_config_name = "node.type.$node_type_id";
+
+    // Simulate config data to import:
+    // - a modified version (modified label) of the node type config.
+    $active = $this->container->get('config.storage');
+    $staging = $this->container->get('config.storage.staging');
+    $this->copyConfig($active, $staging);
+
+    $node_type = $active->read($node_type_config_name);
+    $new_label = 'Test update import field';
+    $node_type['name'] = $new_label;
+    // Save as files in the the staging directory.
+    $staging->write($node_type_config_name, $node_type);
+
+    // Import the content of the staging directory.
+    $this->configImporter()->import();
+
+    // Check that the updated config was correctly imported.
+    $node_type = entity_load('node_type', $node_type_id);
+    $this->assertEqual($node_type->label(), $new_label, 'Node type name has been updated.');
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php
new file mode 100644
index 0000000..593093a
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Tests\Config\NodeImportCreateTest.
+ */
+
+namespace Drupal\node\Tests\Config;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Tests content types as part of config import.
+ */
+class NodeImportCreateTest extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node', 'entity', 'field', 'text', 'field_sql_storage', 'system');
+
+  /**
+   * Set the default field storage backend for fields created during tests.
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', array('config_snapshot'));
+
+    // Set default storage backend.
+    $this->installConfig(array('field'));
+  }
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node config create tests',
+      'description' => 'Create content types during config create method invocation.',
+      'group' => 'Node',
+    );
+  }
+
+  /**
+   * Tests creating a content type during default config import.
+   */
+  public function testImportCreateDefault() {
+    $node_type_id = 'default';
+
+    // Check that the content type does not exist yet.
+    $this->assertFalse(entity_load('node_type', $node_type_id));
+
+    // Enable node_test_config module and check that the content type
+    // shipped in the module's default config is created.
+    $this->container->get('module_handler')->enable(array('node_test_config'));
+    $node_type = entity_load('node_type', $node_type_id);
+    $this->assertTrue($node_type, 'The default content type was created.');
+  }
+
+  /**
+   * Tests creating a content type during config import.
+   */
+  public function testImportCreate() {
+    $node_type_id = 'import';
+    $node_type_config_name = "node.type.$node_type_id";
+
+    // Simulate config data to import.
+    $active = $this->container->get('config.storage');
+    $staging = $this->container->get('config.storage.staging');
+    $this->copyConfig($active, $staging);
+    // Manually add new node type.
+    $src_dir = drupal_get_path('module', 'node_test_config') . '/staging';
+    $this->assertTrue(file_unmanaged_copy("$src_dir/$node_type_config_name.yml", "public://config_staging/$node_type_config_name.yml"));
+
+    // Import the content of the staging directory.
+    $this->configImporter()->import();
+
+    // Check that the content type was created.
+    $node_type = entity_load('node_type', $node_type_id);
+    $this->assertTrue($node_type, 'Import node type from staging was created.');
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php
index f531520..55719bb 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php
@@ -107,7 +107,7 @@ function testUnpublishedNodeCreation() {
     config('system.site')->set('page.front', 'test-page')->save();
 
     // Set "Basic page" content type to be unpublished by default.
-    variable_set('node_options_page', array());
+    config('node.type.page')->set('settings.node.options', array())->save();
 
     // Create a node.
     $edit = array();
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php
index a2bd56c..a592c88 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php
@@ -109,7 +109,7 @@ function testNodeFormButtons() {
     // the initial order of buttons and/or status of the node when creating
     // a node.
     variable_set('node_options_article', array('promote'));
-    $this->refreshVariables();
+    config('node.type.article')->set('settings.node.options.status', 0)->save();
 
     // Verify the buttons on a node add form for an administrator.
     $this->drupalLogin($this->admin_user);
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php
index c72dc25..a1f3a75 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php
@@ -36,7 +36,7 @@ function testPagePostInfo() {
 
     // Set "Basic page" content type to display post information.
     $edit = array();
-    $edit['node_submitted'] = TRUE;
+    $edit['settings[node][submitted]'] = TRUE;
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
 
     // Create a node.
@@ -50,16 +50,11 @@ function testPagePostInfo() {
     $node = $this->drupalGetNodeByTitle($edit["title"]);
     $elements = $this->xpath('//*[contains(@class,:class)]', array(':class' => 'submitted'));
     $this->assertEqual(count($elements), 1, 'Post information is displayed.');
-  }
-
-  /**
-   * Confirms absence of post information on a new node.
-   */
-  function testPageNotPostInfo() {
+    $node->delete();
 
     // Set "Basic page" content type to display post information.
     $edit = array();
-    $edit['node_submitted'] = FALSE;
+    $edit['settings[node][submitted]'] = FALSE;
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
 
     // Create a node.
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php
index d8fa419..22aedb4 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php
@@ -31,12 +31,11 @@ function testNodeTypeCustomizationPersistence() {
     $forum_enable = array($forum_key => "1");
     $forum_disable = array($forum_key => FALSE);
 
-    // Enable forum and verify that the node type is in the DB and is not
-    // disabled.
+    // Enable forum and verify that the node type exists and is not disabled.
     $this->drupalPost('admin/modules', $forum_enable, t('Save configuration'));
-    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
-    $this->assertNotIdentical($disabled, FALSE, 'Forum node type found in the database');
-    $this->assertEqual($disabled, 0, 'Forum node type is not disabled');
+    $forum = entity_load('node_type', 'forum');
+    $this->assertTrue($forum->id(), 'Forum node type found.');
+    $this->assertTrue($forum->isLocked(), 'Forum node type is locked');
 
     // Check that forum node type (uncustomized) shows up.
     $this->drupalGet('node/add');
@@ -53,17 +52,17 @@ function testNodeTypeCustomizationPersistence() {
 
     // Disable forum and check that the node type gets disabled.
     $this->drupalPost('admin/modules', $forum_disable, t('Save configuration'));
-    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
-    $this->assertEqual($disabled, 1, 'Forum node type is disabled');
+    $forum = entity_load('node_type', 'forum');
+    $this->assertTrue($forum->isLocked(), 'Forum node type is node locked');
     $this->drupalGet('node/add');
     $this->assertNoText('forum', 'forum type is not found on node/add');
 
     // Reenable forum and check that the customization survived the module
     // disable.
     $this->drupalPost('admin/modules', $forum_enable, t('Save configuration'));
-    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
-    $this->assertNotIdentical($disabled, FALSE, 'Forum node type found in the database');
-    $this->assertEqual($disabled, 0, 'Forum node type is not disabled');
+    $forum = entity_load('node_type', 'forum');
+    $this->assertTrue($forum->id(), 'Forum node type found.');
+    $this->assertTrue($forum->isLocked(), 'Forum node type is locked');
     $this->drupalGet('node/add');
     $this->assertText($description, 'Customized description found');
 
@@ -72,8 +71,8 @@ function testNodeTypeCustomizationPersistence() {
     $edit = array('uninstall[forum]' => 'forum');
     $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
     $this->drupalPost(NULL, array(), t('Uninstall'));
-    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
-    $this->assertTrue($disabled, 'Forum node type is in the database and is disabled');
+    $forum = entity_load('node_type', 'forum');
+    $this->assertFalse($forum->isLocked(), 'Forum node type is not locked');
     $this->drupalGet('node/add');
     $this->assertNoText('forum', 'forum type is no longer found on node/add');
 
@@ -83,4 +82,5 @@ function testNodeTypeCustomizationPersistence() {
     $this->drupalGet('node/add');
     $this->assertText($description, 'Customized description is found even after uninstall and reenable.');
   }
+
 }
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
index 6a5b5f6..f3307e7 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
@@ -41,9 +41,9 @@ function testNodeTypeGetFunctions() {
 
     $this->assertEqual($node_types['article']->name, $node_names['article'], 'Correct node type base has been returned.');
 
-    $this->assertEqual($node_types['article'], node_type_load('article'), 'Correct node type has been returned.');
-    $this->assertEqual($node_types['article']->name, node_type_get_label('article'), 'Correct node type name has been returned.');
-    $this->assertEqual($node_types['page']->base, node_type_get_base('page'), 'Correct node type base has been returned.');
+    $article = entity_load('node_type', 'article');
+    $this->assertEqual($node_types['article'], $article, 'Correct node type has been returned.');
+    $this->assertEqual($node_types['article']->name, $article->label(), 'Correct node type name has been returned.');
   }
 
   /**
@@ -53,7 +53,7 @@ function testNodeTypeCreation() {
     // Create a content type programmaticaly.
     $type = $this->drupalCreateContentType();
 
-    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $type->type))->fetchField();
+    $type_exists = (bool) entity_load('node_type', $type->type);
     $this->assertTrue($type_exists, 'The new content type has been created in the database.');
 
     // Login a test user.
@@ -72,7 +72,7 @@ function testNodeTypeCreation() {
       'type' => 'foo',
     );
     $this->drupalPost('admin/structure/types/add', $edit, t('Save content type'));
-    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => 'foo'))->fetchField();
+    $type_exists = (bool) entity_load('node_type', 'foo');
     $this->assertTrue($type_exists, 'The new content type has been created in the database.');
   }
 
@@ -130,34 +130,31 @@ function testNodeTypeEditing() {
   }
 
   /**
-   * Tests that node_types_rebuild() correctly handles the 'disabled' flag.
+   * Tests that node types correctly handles their locking.
    */
   function testNodeTypeStatus() {
     // Enable all core node modules, and all types should be active.
-    module_enable(array('book'), FALSE);
-    node_types_rebuild();
+    $this->container->get('module_handler')->enable(array('book'), FALSE);
     $types = node_type_get_types();
     foreach (array('book', 'article', 'page') as $type) {
       $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type)));
-      $this->assertTrue(isset($types[$type]->disabled) && empty($types[$type]->disabled), format_string('%type type is enabled.', array('%type' => $type)));
+      $this->assertFalse($types[$type]->isLocked(), format_string('%type type is not locked.', array('%type' => $type)));
     }
 
     // Disable book module and the respective type should still be active, since
-    // it is not provided by hook_node_info().
-    module_disable(array('book'), FALSE);
-    node_types_rebuild();
+    // it is not provided by shipped configuration entity.
+    $this->container->get('module_handler')->disable(array('book'), FALSE);
     $types = node_type_get_types();
-    $this->assertTrue(isset($types['book']) && empty($types['book']->disabled), "Book module's node type still active.");
-    $this->assertTrue(isset($types['article']) && empty($types['article']->disabled), 'Article node type still active.');
-    $this->assertTrue(isset($types['page']) && empty($types['page']->disabled), 'Basic page node type still active.');
+    $this->assertFalse($types['book']->isLocked(), "Book module's node type still active.");
+    $this->assertFalse($types['article']->isLocked(), 'Article node type still active.');
+    $this->assertFalse($types['page']->isLocked(), 'Basic page node type still active.');
 
     // Re-enable the modules and verify that the types are active again.
-    module_enable(array('book'), FALSE);
-    node_types_rebuild();
+    $this->container->get('module_handler')->enable(array('book'), FALSE);
     $types = node_type_get_types();
     foreach (array('book', 'article', 'page') as $type) {
       $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type)));
-      $this->assertTrue(isset($types[$type]->disabled) && empty($types[$type]->disabled), format_string('%type type is enabled.', array('%type' => $type)));
+      $this->assertFalse($types[$type]->isLocked(), format_string('%type type is not locked.', array('%type' => $type)));
     }
   }
 
@@ -194,6 +191,14 @@ function testNodeTypeDeletion() {
       'The content type is available for deletion.'
     );
     $this->assertText(t('This action cannot be undone.'), 'The node type deletion confirmation form is available.');
+    // Test that forum node type could not be deleted while forum active.
+    $this->container->get('module_handler')->enable(array('forum'));
+    $this->drupalGet('admin/structure/types/manage/forum/delete');
+    $this->assertResponse(403);
+    $this->container->get('module_handler')->disable(array('forum'));
+    $this->container->get('module_handler')->uninstall(array('forum'));
+    $this->drupalGet('admin/structure/types/manage/forum/delete');
+    $this->assertResponse(200);
   }
 
 }
diff --git a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
index ae7529b..b485545 100644
--- a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
@@ -186,7 +186,7 @@ function testPagePreviewWithRevisions() {
     $body_key = "body[$langcode][0][value]";
     $term_key = "{$this->field_name}[$langcode]";
     // Force revision on "Basic page" content.
-    variable_set('node_options_page', array('status', 'revision'));
+    $this->container->get('config.factory')->get('node.type.page')->set('settings.node.options', array('status', 'revision'))->save();
 
     // Fill in node creation form and preview node.
     $edit = array();
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 2214746..3e0cf3c 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -14,7 +14,7 @@
  *
  * Each content type is maintained by a primary module, which is either
  * node.module (for content types created in the user interface) or the module
- * that implements hook_node_info() to define the content type.
+ * that defines the content type by providing configuration file.
  *
  * During node operations (create, insert, update, view, delete, etc.), there
  * are several sets of hooks that get invoked to allow modules to modify the
@@ -844,62 +844,6 @@ function hook_node_view_alter(&$build, \Drupal\Core\Entity\EntityInterface $node
 }
 
 /**
- * Define module-provided node types.
- *
- * This hook allows a module to define one or more of its own node types. For
- * example, the forum module uses it to define a forum node-type named "Forum
- * topic." The name and attributes of each desired node type are specified in an
- * array returned by the hook.
- *
- * Only module-provided node types should be defined through this hook. User-
- * provided (or 'custom') node types should be defined only in the 'node_type'
- * database table, and should be maintained by using the node_type_save() and
- * node_type_delete() functions.
- *
- * @return
- *   An array of information defining the module's node types. The array
- *   contains a sub-array for each node type, with the the machine name of a
- *   content type as the key. Each sub-array has up to 10 attributes.
- *   Possible attributes:
- *   - name: (required) The human-readable name of the node type.
- *   - base: (required) The base string used to construct callbacks
- *     corresponding to this node type (for example, if base is defined as
- *     example_foo, then example_foo_insert will be called when inserting a node
- *     of that type). This string is usually the name of the module, but not
- *     always.
- *   - description: (required) A brief description of the node type.
- *   - help: (optional) Help information shown to the user when creating a node
- *     of this type.
- *   - has_title: (optional) A Boolean indicating whether or not this node type
- *     has a title field.
- *   - title_label: (optional) The label for the title field of this content
- *     type.
- *   - locked: (optional) A Boolean indicating whether the administrator can
- *     change the machine name of this type. FALSE = changeable (not locked),
- *     TRUE = unchangeable (locked).
- *
- * The machine name of a node type should contain only letters, numbers, and
- * underscores. Underscores will be converted into hyphens for the purpose of
- * constructing URLs.
- *
- * All attributes of a node type that are defined through this hook (except for
- * 'locked') can be edited by a site administrator. This includes the
- * machine-readable name of a node type, if 'locked' is set to FALSE.
- *
- * @ingroup node_api_hooks
- */
-function hook_node_info() {
-  return array(
-    'forum' => array(
-      'name' => t('Forum topic'),
-      'base' => 'forum',
-      'description' => t('A <em>forum topic</em> starts a new discussion thread within a forum.'),
-      'title_label' => t('Subject'),
-    )
-  );
-}
-
-/**
  * Provide additional methods of scoring for core search results for nodes.
  *
  * A node's search score is used to rank it among other nodes matched by the
@@ -964,44 +908,33 @@ function hook_ranking() {
 /**
  * Respond to node type creation.
  *
- * This hook is invoked from node_type_save() after the node type is added to
- * the database.
- *
- * @param $info
- *   The node type object that is being created.
+ * @param \Drupal\node\NodeTypeInterface $type
+ *   The node type entity that was created.
  */
-function hook_node_type_insert($info) {
-  drupal_set_message(t('You have just created a content type with a machine name %type.', array('%type' => $info->type)));
+function hook_node_type_insert(\Drupal\node\NodeTypeInterface $type) {
+  drupal_set_message(t('You have just created a content type with a machine name %type.', array('%type' => $type->id())));
 }
 
 /**
  * Respond to node type updates.
  *
- * This hook is invoked from node_type_save() after the node type is updated in
- * the database.
- *
- * @param $info
- *   The node type object that is being updated.
+ * @param \Drupal\node\NodeTypeInterface $type
+ *   The node type entity that was updated.
  */
-function hook_node_type_update($info) {
-  if (!empty($info->old_type) && $info->old_type != $info->type) {
-    $setting = variable_get('comment_' . $info->old_type, COMMENT_NODE_OPEN);
-    variable_del('comment_' . $info->old_type);
-    variable_set('comment_' . $info->type, $setting);
+function hook_node_type_update(\Drupal\node\NodeTypeInterface $type) {
+  if ($type->original->id() != $type->id()) {
+    drupal_set_message(t('You have just changed the machine name of a content type from %old_type to %type.', array('%old_type' => $type->original->id(), '%type' => $type->id())));
   }
 }
 
 /**
  * Respond to node type deletion.
  *
- * This hook is invoked from node_type_delete() after the node type is removed
- * from the database.
- *
- * @param $info
- *   The node type object that is being deleted.
+ * @param \Drupal\node\NodeTypeInterface $type
+ *   The node type entity that was deleted.
  */
-function hook_node_type_delete($info) {
-  variable_del('comment_' . $info->type);
+function hook_node_type_delete(\Drupal\node\NodeTypeInterface $type) {
+  drupal_set_message(t('You have just deleted a content type with the machine name %type.', array('%type' => $type->id())));
 }
 
 /**
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index 0c545b3..d16b875 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -5,6 +5,7 @@
  * Install, update and uninstall functions for the node module.
  */
 
+use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\Language\Language;
 
 /**
@@ -36,7 +37,7 @@ function node_schema() {
         'default' => NULL,
       ),
       'type' => array(
-        'description' => 'The {node_type}.type of this node.',
+        'description' => 'The type of this node.',
         'type' => 'varchar',
         'length' => 32,
         'not null' => TRUE,
@@ -387,100 +388,6 @@ function node_schema() {
     ),
   );
 
-  $schema['node_type'] = array(
-    'description' => 'Stores information about all defined {node} types.',
-    'fields' => array(
-      'type' => array(
-        'description' => 'The machine-readable name of this type.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-      ),
-      'name' => array(
-        'description' => 'The human-readable name of this type.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'base' => array(
-        'description' => 'The base string used to construct callbacks corresponding to this node type.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-      ),
-      'module' => array(
-        'description' => 'The module defining this node type.',
-        'type' => 'varchar',
-        'length' => DRUPAL_EXTENSION_NAME_MAX_LENGTH,
-        'not null' => TRUE,
-      ),
-      'description' => array(
-        'description' => 'A brief description of this type.',
-        'type' => 'text',
-        'not null' => TRUE,
-        'size' => 'medium',
-      ),
-      'help' => array(
-        'description' => 'Help information shown to the user when creating a {node} of this type.',
-        'type' => 'text',
-        'not null' => TRUE,
-        'size' => 'medium',
-      ),
-      'has_title' => array(
-        'description' => 'Boolean indicating whether this type uses the {node}.title field.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'size' => 'tiny',
-      ),
-      'title_label' => array(
-        'description' => 'The label displayed for the title field on the edit form.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'custom' => array(
-        'description' => 'A boolean indicating whether this type is defined by a module (FALSE) or by a user via Add content type (TRUE).',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny',
-      ),
-      'modified' => array(
-        'description' => 'A boolean indicating whether this type has been modified by an administrator; currently not used in any way.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny',
-      ),
-      'locked' => array(
-        'description' => 'A boolean indicating whether the administrator can change the machine name of this type.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny',
-      ),
-      'disabled' => array(
-        'description' => 'A boolean indicating whether the node type is disabled.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny',
-      ),
-      'orig_type' => array(
-        'description' => 'The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-    ),
-    'primary key' => array('type'),
-  );
-
-
   return $schema;
 }
 
@@ -509,17 +416,9 @@ function node_install() {
  */
 function node_uninstall() {
   // Delete node type variables.
-  $types = db_query('SELECT type FROM {node_type}')->fetchCol();
-  foreach ($types as $type) {
-    db_delete('variable')
-      ->condition(db_or()
-        ->condition('name', 'node_preview_' . $type)
-        ->condition('name', 'node_options_' . $type)
-        ->condition('name', 'node_submitted_' . $type)
-        ->condition('name', 'node_permissions_' . $type)
-        ->condition('name', 'node_type_language_translation_enabled_' . $type)
-      )
-      ->execute();
+  $types = config_get_storage_names_with_prefix('node.type.');
+  foreach ($types as $config_name) {
+    $type = config($config_name)->get('type');
     config('language.settings')->clear('node. ' . $type . '.language.default_configuration')->save();
   }
 
@@ -1165,6 +1064,57 @@ function node_update_8019() {
 }
 
 /**
+ * Convert node types into configuration.
+ *
+ * @ingroup config_upgrade
+*/
+function node_update_8020() {
+  $uuid = new Uuid();
+  // Properties to drop: custom, disabled.
+  $locked = array();
+  // Note: {node_type}.name was the label, .type the machine name.
+  $result = db_query('SELECT * FROM {node_type}')
+    ->fetchAllAssoc('type', PDO::FETCH_ASSOC);
+  foreach ($result as $id => $node_type) {
+    $config = config('node.type.' . $id);
+    // Node type.
+    $config->setData($node_type);
+    $config->set('uuid', $uuid->generate());
+    $config->set('langcode', Language::LANGCODE_NOT_SPECIFIED);
+
+    // Node type settings.
+    $variables = db_query('SELECT name, value FROM {variable} WHERE name IN (:names)', array(
+      ':names' => array(
+        'node_submitted_' . $id,
+        'node_preview_' . $id,
+        'node_options_' . $id,
+      ),
+    ))->fetchAllKeyed();
+    $variables = array_map('unserialize', $variables);
+    // There are not necessarily values for all settings, so pollute defaults.
+    $variables += array(
+      'node_submitted_' . $id => TRUE,
+      'node_preview_' . $id => 1, // DRUPAL_OPTIONAL
+      'node_options_' . $id => array('status', 'promote'),
+    );
+    foreach ($variables as $name => $value) {
+      // Turn e.g. 'node_submitted_ID' into 'submitted'.
+      $name = str_replace(array('node_', '_' . $id), '', $name);
+      $config->set('settings.node.' . $name, $value);
+
+      update_variable_del($name);
+    }
+    $config->save();
+    // Convert the 'base' property to state. Note that we could have disabled
+    // modules at this time but we still need to preserve the relation.
+    if ($node_type['base'] !== 'node_content') {
+      $locked[$id] = $node_type['base'];
+    }
+  }
+  Drupal::state()->set('node.type.locked', $locked);
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x"
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index fbdf07d..1730572 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -16,6 +16,7 @@
 use Drupal\Core\Database\Query\SelectExtender;
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
+use Drupal\node\NodeTypeInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Template\Attribute;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
@@ -77,13 +78,6 @@
 const NODE_ACCESS_IGNORE = NULL;
 
 /**
- * Implements hook_rebuild().
- */
-function node_rebuild() {
-  node_types_rebuild();
-}
-
-/**
  * Implements hook_help().
  */
 function node_help($path, $arg) {
@@ -125,8 +119,9 @@ function node_help($path, $arg) {
       return '<p>' . t('Individual content types can have different fields, behaviors, and permissions assigned to them.') . '</p>';
 
     case 'admin/structure/types/manage/%/display':
+      $type =  entity_load('node_type', $arg[4]);
       return '<p>' . t('Content items can be displayed using different view modes: Teaser, Full content, Print, RSS, etc. <em>Teaser</em> is a short format that is typically used in lists of multiple content items. <em>Full content</em> is typically used when the content is displayed on its own page.') . '</p>' .
-        '<p>' . t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', array('%type' => node_type_get_label($arg[4]))) . '</p>';
+        '<p>' . t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', array('%type' => $type->label())) . '</p>';
 
     case 'node/%/revisions':
       return '<p>' . t('Revisions allow you to track differences between multiple versions of your content, and revert back to older versions.') . '</p>';
@@ -163,10 +158,6 @@ function node_theme() {
       'variables' => array('node' => NULL),
       'file' => 'node.pages.inc',
     ),
-    'node_admin_overview' => array(
-      'variables' => array('name' => NULL, 'type' => NULL),
-      'file' => 'content_types.inc',
-    ),
     'node_recent_block' => array(
       'variables' => array('nodes' => NULL),
     ),
@@ -187,9 +178,8 @@ function node_entity_bundle_info() {
   $bundles = array();
   // Bundles must provide a human readable name so we can create help and error
   // messages.
-  node_type_cache_reset();
-  foreach (node_type_get_names() as $type => $name) {
-    $bundles['node'][$type]['label'] = $name;
+  foreach (node_type_get_names() as $id => $label) {
+    $bundles['node'][$id]['label'] = $label;
   }
   return $bundles;
 }
@@ -305,63 +295,43 @@ function node_mark($nid, $timestamp) {
  * Returns a list of all the available node types.
  *
  * This list can include types that are queued for addition or deletion.
- * See _node_types_build() for details.
  *
- * @return
- *   An array of node types, as objects, keyed by the type.
+ * @return array
+ *   An array of node type entities, keyed by ID.
  *
- * @see _node_types_build()
  * @see node_type_load()
  */
 function node_type_get_types() {
-  return _node_types_build()->types;
-}
-
-/**
- * Returns the node type base of the passed node or node type string.
- *
- * The base indicates which module implements this node type and is used to
- * execute node-type-specific hooks. For types defined in the user interface
- * and managed by node.module, the base is 'node_content'.
- *
- * @param string $type
- *   A string that indicates the node type to return.
- *
- * @return string|false
- *   The node type base or FALSE if the node type is not found.
- */
-function node_type_get_base($type) {
-  $types = _node_types_build()->types;
-  return isset($types[$type]) && isset($types[$type]->base) ? $types[$type]->base : FALSE;
+  return entity_load_multiple('node_type');
 }
 
 /**
  * Returns a list of available node type names.
  *
  * This list can include types that are queued for addition or deletion.
- * See _node_types_build() for details.
  *
- * @return
+ * @return array
  *   An array of node type labels, keyed by the node type name.
- *
- * @see _node_types_build()
  */
 function node_type_get_names() {
-  return _node_types_build()->names;
-}
-
-/**
- * Returns the node type label for the passed node type name.
- *
- * @param string $name
- *   The machine name of a node type.
- *
- * @return string|false
- *   The node type label or FALSE if the node type is not found.
- */
-function node_type_get_label($name) {
-  $types = _node_types_build()->names;
-  return isset($types[$name]) ? $types[$name] : FALSE;
+  $cid = 'node_type:names:' . language(Language::TYPE_INTERFACE)->langcode;
+  if ($cache = cache()->get($cid)) {
+    return $cache->data;
+  }
+  // Not using node_type_get_types() or entity_load_multiple() here, to allow
+  // this function being used in hook_entity_info() implementations.
+  // @todo Consider to convert this into a generic config entity helper.
+  $config_names = config_get_storage_names_with_prefix('node.type.');
+  $names = array();
+  foreach ($config_names as $config_name) {
+    $config = config($config_name);
+    $names[$config->get('type')] = $config->get('name');
+  }
+  cache()->set($cid, $names, CacheBackendInterface::CACHE_PERMANENT, array(
+    'node_type' => array_keys($names),
+    'node_types' => TRUE,
+  ));
+  return $names;
 }
 
 /**
@@ -372,152 +342,45 @@ function node_type_get_label($name) {
  *
  * @return string|false
  *   The node type label or FALSE if the node type is not found.
- */
-function node_get_type_label(EntityInterface $node) {
-  $types = _node_types_build()->names;
-  return isset($types[$node->type]) ? $types[$node->type] : FALSE;
-}
-
-/**
- * Title callback: Returns the sanitized node type name.
  *
- * @param $node_type
- *   The node type object.
- *
- * @return
- *   The node type name that is safe for printing.
+ * @todo Add this as generic helper method for config entities representing
+ *   entity bundles.
  */
-function node_type_get_clean_name($node_type) {
-  return check_plain($node_type->name);
+function node_get_type_label(EntityInterface $node) {
+  $type = entity_load('node_type', $node->bundle());
+  return $type ? $type->label() : FALSE;
 }
 
 /**
  * Description callback: Returns the node type description.
  *
- * @param $node_type
+ * @param \Drupal\node\NodeTypeInterface $node_type
  *   The node type object.
  *
- * @return
+ * @return string
  *   The node type description.
  */
-function node_type_get_description($node_type) {
+function node_type_get_description(NodeTypeInterface $node_type) {
   return $node_type->description;
 }
 
 /**
- * Updates the database cache of node types.
- *
- * All new module-defined node types are saved to the database via a call to
- * node_type_save(), and obsolete ones are deleted via a call to
- * node_type_delete(). See _node_types_build() for an explanation of the new
- * and obsolete types.
- *
- * @see _node_types_build()
- */
-function node_types_rebuild() {
-  _node_types_build(TRUE);
-}
-
-/**
  * Menu argument loader: Loads a node type by string.
  *
  * @param $name
  *   The machine name of a node type to load.
  *
- * @return
+ * @return \Drupal\node\NodeTypeInterface
  *   A node type object or FALSE if $name does not exist.
  */
 function node_type_load($name) {
-  $types = _node_types_build()->types;
-  return isset($types[$name]) ? $types[$name] : FALSE;
-}
-
-/**
- * Saves a node type to the database.
- *
- * @param object $info
- *   The node type to save; an object with the following properties:
- *   - type: A string giving the machine name of the node type.
- *   - name: A string giving the human-readable name of the node type.
- *   - base: A string that indicates the base string for hook functions. For
- *     example, 'node_content' is the value used by the UI when creating a new
- *     node type.
- *   - description: A string that describes the node type.
- *   - help: A string giving the help information shown to the user when
- *     creating a node of this type.
- *   - custom: TRUE or FALSE indicating whether this type is defined by a module
- *     (FALSE) or by a user (TRUE) via Add Content Type.
- *   - modified: TRUE or FALSE indicating whether this type has been modified by
- *     an administrator. Currently not used in any way.
- *   - locked: TRUE or FALSE indicating whether the administrator can change the
- *     machine name of this type.
- *   - disabled: TRUE or FALSE indicating whether this type has been disabled.
- *   - has_title: TRUE or FALSE indicating whether this type uses the node title
- *     field.
- *   - title_label: A string containing the label for the title.
- *   - module: A string giving the module defining this type of node.
- *   - orig_type: A string giving the original machine-readable name of this
- *     node type. This may be different from the current type name if the locked
- *     field is 0.
- *
- * @return int
- *   A status flag indicating the outcome of the operation, either SAVED_NEW or
- *   SAVED_UPDATED.
- */
-function node_type_save($info) {
-  $existing_type = !empty($info->old_type) ? $info->old_type : $info->type;
-  $is_existing = (bool) db_query_range('SELECT 1 FROM {node_type} WHERE type = :type', 0, 1, array(':type' => $existing_type))->fetchField();
-  $type = node_type_set_defaults($info);
-
-  $fields = array(
-    'type' => (string) $type->type,
-    'name' => (string) $type->name,
-    'base' => (string) $type->base,
-    'has_title' => (int) $type->has_title,
-    'title_label' => (string) $type->title_label,
-    'description' => (string) $type->description,
-    'help' => (string) $type->help,
-    'custom' => (int) $type->custom,
-    'modified' => (int) $type->modified,
-    'locked' => (int) $type->locked,
-    'disabled' => (int) $type->disabled,
-    'module' => $type->module,
-  );
-
-  if ($is_existing) {
-    db_update('node_type')
-      ->fields($fields)
-      ->condition('type', $existing_type)
-      ->execute();
-
-    if (!empty($type->old_type) && $type->old_type != $type->type) {
-      entity_invoke_bundle_hook('rename', 'node', $type->old_type, $type->type);
-    }
-    module_invoke_all('node_type_update', $type);
-    $status = SAVED_UPDATED;
-  }
-  else {
-    $fields['orig_type'] = (string) $type->orig_type;
-    db_insert('node_type')
-      ->fields($fields)
-      ->execute();
-
-    entity_invoke_bundle_hook('create', 'node', $type->type);
-
-    module_invoke_all('node_type_insert', $type);
-    $status = SAVED_NEW;
-  }
-
-  // Clear the node type cache.
-  node_type_cache_reset();
-
-  return $status;
+  return entity_load('node_type', $name);
 }
 
 /**
  * Adds the default body field to a node type.
  *
- * @param $type
+ * @param \Drupal\node\NodeTypeInterface $type
  *   A node type object.
  * @param $label
  *   (optional) The label for the body instance.
@@ -525,10 +388,10 @@ function node_type_save($info) {
  * @return
  *   Body field instance.
  */
-function node_add_body_field($type, $label = 'Body') {
+function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
    // Add or remove the body field, as needed.
   $field = field_info_field('body');
-  $instance = field_info_instance('node', 'body', $type->type);
+  $instance = field_info_instance('node', 'body', $type->id());
   if (empty($field)) {
     $field = entity_create('field_entity', array(
       'field_name' => 'body',
@@ -541,7 +404,7 @@ function node_add_body_field($type, $label = 'Body') {
     $instance = entity_create('field_instance', array(
       'field_name' => 'body',
       'entity_type' => 'node',
-      'bundle' => $type->type,
+      'bundle' => $type->id(),
       'label' => $label,
       'settings' => array('display_summary' => TRUE),
     ));
@@ -615,198 +478,24 @@ function node_field_extra_fields() {
 }
 
 /**
- * Deletes a node type from the database.
- *
- * @param $name
- *   The machine name of the node type to delete.
- */
-function node_type_delete($name) {
-  $type = node_type_load($name);
-  db_delete('node_type')
-    ->condition('type', $name)
-    ->execute();
-  entity_invoke_bundle_hook('delete', 'node', $name);
-  module_invoke_all('node_type_delete', $type);
-
-  // Clear the node type cache.
-  node_type_cache_reset();
-}
-
-/**
  * Updates all nodes of one type to be of another type.
  *
- * @param $old_type
+ * @param string $old_id
  *   The current node type of the nodes.
- * @param $type
+ * @param string $new_id
  *   The new node type of the nodes.
  *
  * @return
  *   The number of nodes whose node type field was modified.
  */
-function node_type_update_nodes($old_type, $type) {
+function node_type_update_nodes($old_id, $new_id) {
   return db_update('node')
-    ->fields(array('type' => $type))
-    ->condition('type', $old_type)
+    ->fields(array('type' => $new_id))
+    ->condition('type', $old_id)
     ->execute();
 }
 
 /**
- * Builds and returns the list of available node types.
- *
- * The list of types is built by invoking hook_node_info() on all modules and
- * comparing this information with the node types in the {node_type} table.
- * These two information sources are not synchronized during module installation
- * until node_types_rebuild() is called.
- *
- * @param $rebuild
- *  (optional) TRUE to rebuild node types. Equivalent to calling
- *  node_types_rebuild(). Defaults to FALSE.
- *
- * @return
- *   An object with two properties:
- *   - names: Associative array of the names of node types, keyed by the type.
- *   - types: Associative array of node type objects, keyed by the type.
- *   Both of these arrays will include new types that have been defined by
- *   hook_node_info() implementations but not yet saved in the {node_type}
- *   table. These are indicated in the type object by $type->is_new being set
- *   to the value 1. These arrays will also include obsolete types: types that
- *   were previously defined by modules that have now been disabled, or for
- *   whatever reason are no longer being defined in hook_node_info()
- *   implementations, but are still in the database. These are indicated in the
- *   type object by $type->disabled being set to TRUE.
- */
-function _node_types_build($rebuild = FALSE) {
-  $cid = 'node_types:' . language(Language::TYPE_INTERFACE)->langcode;
-
-  if (!$rebuild) {
-    $_node_types = &drupal_static(__FUNCTION__);
-    if (isset($_node_types)) {
-      return $_node_types;
-    }
-    if ($cache = cache()->get($cid)) {
-      $_node_types = $cache->data;
-      return $_node_types;
-    }
-  }
-
-  $_node_types = (object) array('types' => array(), 'names' => array());
-
-  foreach (module_implements('node_info') as $module) {
-    $info_array = module_invoke($module, 'node_info');
-    foreach ($info_array as $type => $info) {
-      $info['type'] = $type;
-      $_node_types->types[$type] = node_type_set_defaults($info);
-      $_node_types->types[$type]->module = $module;
-      $_node_types->names[$type] = $info['name'];
-    }
-  }
-  $query = db_select('node_type', 'nt')
-    ->addTag('node_type_access')
-    ->fields('nt')
-    ->orderBy('nt.type', 'ASC');
-  if (!$rebuild) {
-    $query->condition('disabled', 0);
-  }
-  foreach ($query->execute() as $type_object) {
-    $type_db = $type_object->type;
-    // Original disabled value.
-    $disabled = $type_object->disabled;
-    // Check for node types from disabled modules and mark their types for removal.
-    // Types defined by the node module in the database (rather than by a separate
-    // module using hook_node_info) have a base value of 'node_content'. The isset()
-    // check prevents errors on old (pre-Drupal 7) databases.
-    if (isset($type_object->base) && $type_object->base != 'node_content' && empty($_node_types->types[$type_db])) {
-      $type_object->disabled = TRUE;
-    }
-    if (isset($_node_types->types[$type_db])) {
-      $type_object->disabled = FALSE;
-    }
-    if (!isset($_node_types->types[$type_db]) || $type_object->modified) {
-      $_node_types->types[$type_db] = $type_object;
-      $_node_types->names[$type_db] = $type_object->name;
-
-      if ($type_db != $type_object->orig_type) {
-        unset($_node_types->types[$type_object->orig_type]);
-        unset($_node_types->names[$type_object->orig_type]);
-      }
-    }
-    $_node_types->types[$type_db]->disabled = $type_object->disabled;
-    $_node_types->types[$type_db]->disabled_changed = $disabled != $type_object->disabled;
-  }
-
-  if ($rebuild) {
-    foreach ($_node_types->types as $type => $type_object) {
-      if (!empty($type_object->is_new) || !empty($type_object->disabled_changed)) {
-        node_type_save($type_object);
-      }
-    }
-  }
-
-  asort($_node_types->names);
-
-  cache()->set($cid, $_node_types, CacheBackendInterface::CACHE_PERMANENT, array('node_types' => TRUE));
-
-  return $_node_types;
-}
-
-/**
- * Clears the node type cache.
- */
-function node_type_cache_reset() {
-  cache()->deleteTags(array('node_types' => TRUE));
-  drupal_static_reset('_node_types_build');
-}
-
-/**
- * Sets the default values for a node type.
- *
- * The defaults are appropriate for a type defined through hook_node_info(),
- * since 'custom' is TRUE for types defined in the user interface, and FALSE
- * for types defined by modules. (The 'custom' flag prevents types from being
- * deleted through the user interface.) Also, the default for 'locked' is TRUE,
- * which prevents users from changing the machine name of the type.
- *
- * @param $info
- *   (optional) An object or array containing values to override the defaults.
- *   See hook_node_info() for details on what the array elements mean. Defaults
- *   to an empty array.
- *
- * @return
- *   A node type object, with missing values in $info set to their defaults.
- *
- * @see hook_node_info()
- */
-function node_type_set_defaults($info = array()) {
-  $info = (array) $info;
-  $new_type = $info + array(
-    'type' => '',
-    'name' => '',
-    'base' => '',
-    'description' => '',
-    'help' => '',
-    'custom' => 0,
-    'modified' => 0,
-    'locked' => 1,
-    'disabled' => 0,
-    'is_new' => 1,
-    'has_title' => 1,
-    'title_label' => 'Title',
-  );
-  $new_type = (object) $new_type;
-
-  // If the type has no title, set an empty label.
-  if (!$new_type->has_title) {
-    $new_type->title_label = '';
-  }
-  if (empty($new_type->module)) {
-    $new_type->module = $new_type->base == 'node_content' ? 'node' : '';
-  }
-  $new_type->orig_type = isset($info['type']) ? $info['type'] : '';
-
-  return $new_type;
-}
-
-/**
  * Implements hook_rdf_mapping().
  */
 function node_rdf_mapping() {
@@ -1066,7 +755,9 @@ function template_preprocess_node(&$variables) {
   field_attach_preprocess($node, $variables['content'], $variables);
 
   // Display post information only on certain node types.
-  if (variable_get('node_submitted_' . $node->type, TRUE)) {
+  // Avoid loading the entire node type config entity here.
+  $submitted = Drupal::config('node.type.' . $node->type)->get('settings.node.submitted') ?: TRUE;
+  if ($submitted) {
     $variables['display_submitted'] = TRUE;
     $variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['name'], '!datetime' => $variables['date']));
     if (theme_get_setting('features.node_user_picture')) {
@@ -1581,9 +1272,7 @@ function node_menu() {
   $items['admin/structure/types'] = array(
     'title' => 'Content types',
     'description' => 'Manage content types, including default status, front page promotion, comment settings, etc.',
-    'page callback' => 'node_overview_types',
-    'access arguments' => array('administer content types'),
-    'file' => 'content_types.inc',
+    'route_name' => 'node_overview_types',
   );
   $items['admin/structure/types/list'] = array(
     'title' => 'List',
@@ -1591,20 +1280,14 @@ function node_menu() {
   );
   $items['admin/structure/types/add'] = array(
     'title' => 'Add content type',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_type_form'),
-    'access arguments' => array('administer content types'),
+    'route_name' => 'node_type_add',
     'type' => MENU_LOCAL_ACTION,
-    'file' => 'content_types.inc',
   );
   $items['admin/structure/types/manage/%node_type'] = array(
     'title' => 'Edit content type',
-    'title callback' => 'node_type_page_title',
+    'title callback' => 'entity_page_label',
     'title arguments' => array(4),
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('node_type_form', 4),
-    'access arguments' => array('administer content types'),
-    'file' => 'content_types.inc',
+    'route_name' => 'node_type_edit',
   );
   $items['admin/structure/types/manage/%node_type/edit'] = array(
     'title' => 'Edit',
@@ -1612,9 +1295,7 @@ function node_menu() {
   );
   $items['admin/structure/types/manage/%node_type/delete'] = array(
     'title' => 'Delete',
-    'page arguments' => array('node_type_delete_confirm', 4),
-    'access arguments' => array('administer content types'),
-    'file' => 'content_types.inc',
+    'route_name' => 'node_type_delete_confirm',
   );
   $items['node/add'] = array(
     'title' => 'Add content',
@@ -1623,7 +1304,7 @@ function node_menu() {
     'file' => 'node.pages.inc',
   );
   $items['node/add/%node_type'] = array(
-    'title callback' => 'node_type_get_clean_name',
+    'title callback' => 'entity_page_label',
     'title arguments' => array(2),
     'page callback' => 'node_add',
     'page arguments' => array(2),
@@ -1717,21 +1398,6 @@ function node_menu_local_tasks(&$data, $router_item, $root_path) {
 }
 
 /**
- * Title callback: Provides the title for a node type edit form.
- *
- * @param $type
- *   The node type object.
- *
- * @return string
- *   An unsanitized string that is the title of the node type edit form.
- *
- * @see node_menu()
- */
-function node_type_page_title($type) {
-  return $type->name;
-}
-
-/**
  * Title callback: Displays the node's title.
  *
  * @param \Drupal\Core\Entity\EntityInterface $node
@@ -1938,6 +1604,27 @@ function node_form_block_form_alter(&$form, &$form_state) {
 }
 
 /**
+ * Implements hook_modules_uninstalled().
+ */
+function node_modules_uninstalled($modules) {
+  // Remove module-specific settings from all node types.
+  $config_names = config_get_storage_names_with_prefix('node.type.');
+  foreach ($config_names as $config_name) {
+    $config = config($config_name);
+    $changed = FALSE;
+    foreach ($modules as $module) {
+      if ($config->get('settings.' . $module)) {
+        $config->clear('settings.' . $module);
+        $changed = TRUE;
+      }
+    }
+    if ($changed) {
+      $config->save();
+    }
+  }
+}
+
+/**
  * Implements hook_block_access().
  *
  * Checks the content type specific visibility settings and removes the block
@@ -2463,8 +2150,10 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) {
  */
 function node_access($op, $node, $account = NULL, $langcode = NULL) {
   if (!$node instanceof EntityInterface) {
-    $type = is_object($node) ? $node->type : $node;
-    $node = entity_create('node', array('type' => $type));
+    $node = entity_create('node', array('type' => $node));
+  }
+  elseif ($node instanceof NodeTypeInterface) {
+    $node = entity_create('node', array('type' => $node->id()));
   }
 
   // If no language code was provided, default to the node's langcode.
@@ -2580,7 +2269,8 @@ function node_list_permissions($type) {
 function node_permissions_get_configured_types() {
   $configured_types = array();
   foreach (node_type_get_types() as $name => $type) {
-    if (variable_get('node_permissions_' . $name, 1)) {
+    $node_settings = $type->getModuleSettings('node');
+    if (!isset($node_settings['permissions']) || !empty($node_settings['permissions'])) {
       $configured_types[$name] = $type;
     }
   }
diff --git a/core/modules/node/node.routing.yml b/core/modules/node/node.routing.yml
index ce897f5..9204a2b 100644
--- a/core/modules/node/node.routing.yml
+++ b/core/modules/node/node.routing.yml
@@ -4,9 +4,46 @@ node_multiple_delete_confirm:
     _form: '\Drupal\node\Form\DeleteMultiple'
   requirements:
     _permission: 'administer nodes'
+
 node_page_edit:
   pattern: '/node/{node}/edit'
   defaults:
     _entity_form: 'node.edit'
   requirements:
     _entity_access: 'node.update'
+
+node_overview_types:
+  pattern: '/admin/structure/types'
+  defaults:
+    _content: '\Drupal\Core\Entity\Controller\EntityListController::listing'
+    entity_type: 'node_type'
+  requirements:
+    _permission: 'administer content types'
+
+node_type_add:
+  pattern: '/admin/structure/types/add'
+  defaults:
+    _entity_form: 'node_type.add'
+  requirements:
+    _permission: 'administer content types'
+
+node_type_edit:
+  pattern: '/admin/structure/types/manage/{node_type}'
+  defaults:
+    _entity_form: 'node_type.edit'
+  requirements:
+    _permission: 'administer content types'
+
+node_type_edit_default:
+  pattern: '/admin/structure/types/manage/{node_type}/edit'
+  defaults:
+    _entity_form: 'node_type.edit'
+  requirements:
+    _permission: 'administer content types'
+
+node_type_delete_confirm:
+  pattern: '/admin/structure/types/manage/{node_type}/delete'
+  defaults:
+    _entity_form: 'node_type.delete'
+  requirements:
+    _entity_access: 'node_type.delete'
diff --git a/core/modules/node/tests/modules/node_test_config/config/node.type.default.yml b/core/modules/node/tests/modules/node_test_config/config/node.type.default.yml
new file mode 100644
index 0000000..1e17673
--- /dev/null
+++ b/core/modules/node/tests/modules/node_test_config/config/node.type.default.yml
@@ -0,0 +1,18 @@
+type: default
+uuid: ca226632-3186-42a2-8440-a526f20840af
+name: Default
+description: 'Default description.'
+help: ''
+has_title: '1'
+title_label: Title
+settings:
+  node:
+    preview: '1'
+    options:
+      status: status
+      promote: promote
+      sticky: '0'
+      revision: '0'
+    submitted: '1'
+status: '1'
+langcode: und
diff --git a/core/modules/node/tests/modules/node_test_config/node_test_config.info.yml b/core/modules/node/tests/modules/node_test_config/node_test_config.info.yml
new file mode 100644
index 0000000..948b4a5
--- /dev/null
+++ b/core/modules/node/tests/modules/node_test_config/node_test_config.info.yml
@@ -0,0 +1,7 @@
+name: 'Node configuration tests'
+type: module
+description: 'Support module for node configuration tests.'
+core: 8.x
+package: Testing
+version: VERSION
+hidden: TRUE
diff --git a/core/modules/node/tests/modules/node_test_config/node_test_config.module b/core/modules/node/tests/modules/node_test_config/node_test_config.module
new file mode 100644
index 0000000..00522b5
--- /dev/null
+++ b/core/modules/node/tests/modules/node_test_config/node_test_config.module
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Helper module for node configuration tests.
+ */
diff --git a/core/modules/node/tests/modules/node_test_config/staging/node.type.import.yml b/core/modules/node/tests/modules/node_test_config/staging/node.type.import.yml
new file mode 100644
index 0000000..f2a4f4a
--- /dev/null
+++ b/core/modules/node/tests/modules/node_test_config/staging/node.type.import.yml
@@ -0,0 +1,18 @@
+type: import
+uuid: 1a720d40-7bcd-41e3-ae4d-08d1cad4ac2a
+name: Import
+description: 'Import description.'
+help: ''
+has_title: '1'
+title_label: Title
+settings:
+  node:
+    preview: '1'
+    options:
+      status: status
+      promote: promote
+      sticky: '0'
+      revision: '0'
+    submitted: '1'
+status: '1'
+langcode: und
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
index 4bad46b..808fe2a 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
@@ -166,6 +166,11 @@ protected function entityValues($entity_type) {
         );
       case 'node':
         return array('title' => $this->randomString(), 'type' => $this->randomString());
+      case 'node_type':
+        return array(
+          'type' => 'article',
+          'name' => $this->randomName(),
+        );
       case 'user':
         return array('name' => $this->randomName());
       default:
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
index 4615b39..a7be5be 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
@@ -110,7 +110,7 @@ function testEnableModulesInstallContainer() {
     // Install Node module.
     $this->enableModules(array('field_sql_storage', 'field', 'node'));
 
-    $this->installSchema('node', array('node_type', 'node', 'node_field_data'));
+    $this->installSchema('node', array('node', 'node_field_data'));
     // Perform an entity query against node.
     $query = \Drupal::entityQuery('node');
     // Disable node access checks, since User module is not enabled.
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 68708ad..8e295b3 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -292,48 +292,32 @@ protected function drupalCreateNode(array $settings = array()) {
   /**
    * Creates a custom content type based on default settings.
    *
-   * @param $settings
+   * @param array $values
    *   An array of settings to change from the defaults.
    *   Example: 'type' => 'foo'.
-   * @return
+   *
+   * @return \Drupal\node\Plugin\Core\Entity\NodeType
    *   Created content type.
    */
-  protected function drupalCreateContentType($settings = array()) {
+  protected function drupalCreateContentType(array $values = array()) {
     // Find a non-existent random type name.
-    do {
-      $name = strtolower($this->randomName(8));
-    } while (node_type_load($name));
-
-    // Populate defaults array.
-    $defaults = array(
-      'type' => $name,
-      'name' => $name,
-      'base' => 'node_content',
-      'description' => '',
-      'help' => '',
-      'title_label' => 'Title',
-      'body_label' => 'Body',
-      'has_title' => 1,
-      'has_body' => 1,
-    );
-    // Imposed values for a custom type.
-    $forced = array(
-      'orig_type' => '',
-      'old_type' => '',
-      'module' => 'node',
-      'custom' => 1,
-      'modified' => 1,
-      'locked' => 0,
+    if (!isset($values['type'])) {
+      do {
+        $id = strtolower($this->randomName(8));
+      } while (node_type_load($id));
+    }
+    else {
+      $id = $values['type'];
+    }
+    $values += array(
+      'type' => $id,
+      'name' => $id,
     );
-    $type = $forced + $settings + $defaults;
-    $type = (object) $type;
-
-    $saved_type = node_type_save($type);
-    node_types_rebuild();
+    $type = entity_create('node_type', $values);
+    $status = $type->save();
     menu_router_rebuild();
-    node_add_body_field($type);
 
-    $this->assertEqual($saved_type, SAVED_NEW, t('Created content type %type.', array('%type' => $type->type)));
+    $this->assertEqual($status, SAVED_NEW, t('Created content type %type.', array('%type' => $type->id())));
 
     // Reset permissions so that permissions for this content type are available.
     $this->checkPermissions(array(), TRUE);
diff --git a/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
index e191efe..26ee375 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
@@ -32,6 +32,8 @@ public static function getInfo() {
    * Submit the condition_node_type_test_form to test condition forms.
    */
   function testConfigForm() {
+    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Page'));
+    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
     $article = entity_create('node', array('type' => 'article', 'title' => $this->randomName()));
     $article->save();
     $this->drupalGet('condition_test');
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
index 0ba07bc..68b2525 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
@@ -32,7 +32,7 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     $this->installSchema('user', array('users_roles', 'users_data'));
-    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_type', 'node_access'));
+    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
index 3649529..055b014 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
@@ -44,7 +44,7 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     $this->installSchema('user', array('users_roles', 'users_data'));
-    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_type', 'node_access'));
+    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
index 48b04ba..8e7eea4 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -36,7 +36,7 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     $this->installSchema('user', array('users_roles', 'users_data'));
-    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_type', 'node_access'));
+    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
     $this->installSchema('entity_test', array(
       'entity_test_mul',
       'entity_test_mul_property_data',
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
index 5d5fb63..b04e2d8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -27,11 +27,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('node', 'node_type');
-  }
-
   /**
    * Tests basic context definition and value getters and setters.
    */
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
index 33f7903..9fedb35 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
@@ -95,9 +95,10 @@ public function testFilledStandardUpgrade() {
     $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
 
     // Verify that the blog node type has been assigned to node module.
-    $blog_type = node_type_load('blog');
-    $this->assertEqual($blog_type->module, 'node', "Content type 'blog' has been reassigned from the blog module to the node module.");
-    $this->assertEqual($blog_type->base, 'node_content', "The base string used to construct callbacks corresponding to content type 'Blog' has been reassigned to 'node_content'.");
+    $node_type = entity_load('node_type', 'blog');
+    $this->assertFalse($node_type->isLocked(), "Content type 'blog' has been reassigned from the blog module to the node module.");
+    $node_type = entity_load('node_type', 'forum');
+    $this->assertTrue($node_type->isLocked(), "The base string used to construct callbacks corresponding to content type 'Forum' has been reassigned to forum module.");
 
     // Each entity type has a 'full' view mode, ensure it was migrated.
     $all_view_modes = entity_get_view_modes();
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index e9e69c5..36e9f77 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -2416,7 +2416,7 @@ function hook_schema() {
         'default' => 0,
       ),
       'type' => array(
-        'description' => 'The {node_type} of this node.',
+        'description' => 'The type of this node.',
         'type' => 'varchar',
         'length' => 32,
         'not null' => TRUE,
diff --git a/core/modules/system/tests/modules/condition_test/condition_test.module b/core/modules/system/tests/modules/condition_test/condition_test.module
index 1310b21..b3d9bbc 100644
--- a/core/modules/system/tests/modules/condition_test/condition_test.module
+++ b/core/modules/system/tests/modules/condition_test/condition_test.module
@@ -1,21 +1 @@
 <?php
-
-/**
- * Implements hook_node_info().
- */
-function condition_test_node_info() {
-  return array(
-    'article' => array(
-      'name' => t('Article'),
-      'base' => 'article',
-      'description' => t('An article content type'),
-      'title_label' => t('Subject'),
-    ),
-    'page' => array(
-      'name' => t('Page'),
-      'base' => 'page',
-      'description' => t('A page content type'),
-      'title_label' => t('Subject'),
-    ),
-  );
-}
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
index 4e23cd8..e7c7031 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
@@ -67,14 +67,9 @@ function setUp() {
    * @see http://drupal.org/node/1708692
    */
   protected function mockStandardInstall() {
-    $type = array(
+    $type = $this->drupalCreateContentType(array(
       'type' => 'article',
-    );
-
-    $type = node_type_set_defaults($type);
-    node_type_save($type);
-    node_add_body_field($type);
-
+    ));
     // Create the vocabulary for the tag field.
     $this->vocabulary = entity_create('taxonomy_vocabulary',  array(
       'name' => 'Views testing tags',
diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module
index e8e872e..2d50934 100644
--- a/core/modules/translation/translation.module
+++ b/core/modules/translation/translation.module
@@ -166,7 +166,7 @@ function translation_form_node_type_form_alter(&$form, &$form_state) {
   $form['language']['node_type_language_translation_enabled'] = array(
     '#type' => 'checkbox',
     '#title' => t('Enable translation'),
-    '#default_value' => variable_get('node_type_language_translation_enabled_' . $form['#node_type']->type, FALSE),
+    '#default_value' => variable_get('node_type_language_translation_enabled_' . $form_state['controller']->getEntity()->id(), FALSE),
     '#element_validate' => array('translation_node_type_language_translation_enabled_validate'),
     '#prefix' => "<label class='form-item-node-type-language-translation-enabled'>" . t('Translation') . "</label>",
   );
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
index 894363d..37d4d81 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
@@ -81,7 +81,7 @@ public static function getInfo() {
 
   protected function setUpFixtures() {
     $this->installSchema('user', array('users'));
-    $this->installSchema('node', array('node_type', 'node', 'node_field_data'));
+    $this->installSchema('node', array('node', 'node_field_data'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
     parent::setUpFixtures();
 
diff --git a/core/profiles/standard/config/node.type.article.yml b/core/profiles/standard/config/node.type.article.yml
new file mode 100644
index 0000000..4bb97a4
--- /dev/null
+++ b/core/profiles/standard/config/node.type.article.yml
@@ -0,0 +1,18 @@
+type: article
+uuid: 38fcdfbf-92a0-43d3-af30-8395cba668d4
+name: Article
+description: 'Use <em>articles</em> for time-sensitive content like news, press releases or blog posts.'
+help: ''
+has_title: '1'
+title_label: Title
+settings:
+  node:
+    preview: '1'
+    options:
+      status: status
+      promote: promote
+      sticky: '0'
+      revision: '0'
+    submitted: '1'
+status: '1'
+langcode: und
diff --git a/core/profiles/standard/config/node.type.page.yml b/core/profiles/standard/config/node.type.page.yml
new file mode 100644
index 0000000..987f75c
--- /dev/null
+++ b/core/profiles/standard/config/node.type.page.yml
@@ -0,0 +1,18 @@
+type: page
+uuid: f77b56af-2b34-4a2f-b7e9-2dcadfdc80d0
+name: 'Basic page'
+description: 'Use <em>basic pages</em> for your static content, such as an ''About us'' page.'
+help: ''
+has_title: '1'
+title_label: Title
+settings:
+  node:
+    preview: '1'
+    options:
+      status: status
+      promote: '0'
+      sticky: '0'
+      revision: '0'
+    submitted: '0'
+status: '1'
+langcode: und
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index b465f35..5c29f4d 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -24,43 +24,9 @@ function standard_install() {
   // Set front page to "node".
   config('system.site')->set('page.front', 'node')->save();
 
-  // Insert default pre-defined node types into the database. For a complete
-  // list of available node type attributes, refer to the node type API
-  // documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
-  $types = array(
-    array(
-      'type' => 'page',
-      'name' => t('Basic page'),
-      'base' => 'node_content',
-      'description' => t("Use <em>basic pages</em> for your static content, such as an 'About us' page."),
-      'custom' => 1,
-      'modified' => 1,
-      'locked' => 0,
-    ),
-    array(
-      'type' => 'article',
-      'name' => t('Article'),
-      'base' => 'node_content',
-      'description' => t('Use <em>articles</em> for time-sensitive content like news, press releases or blog posts.'),
-      'custom' => 1,
-      'modified' => 1,
-      'locked' => 0,
-    ),
-  );
-
-  foreach ($types as $type) {
-    $type = node_type_set_defaults($type);
-    node_type_save($type);
-    node_add_body_field($type);
-  }
-
-  // Default "Basic page" to not be promoted and have comments disabled.
-  variable_set('node_options_page', array('status'));
+  // Default "Basic page" to have comments disabled.
   variable_set('comment_page', COMMENT_NODE_HIDDEN);
 
-  // Don't display date and author information for "Basic page" nodes by default.
-  variable_set('node_submitted_page', FALSE);
-
   // Allow visitor account creation with administrative approval.
   $user_settings = config('user.settings');
   $user_settings->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 49b1a44..11af8e7 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -680,6 +680,21 @@ function simpletest_script_get_test_list() {
     simpletest_script_print_error('No valid tests were specified.');
     exit;
   }
+
+  $test_list = array(
+    'Drupal\book\Tests\BookTest',
+    'Drupal\comment\Tests\CommentLanguageTest',
+    'Drupal\language\Tests\LanguageConfigurationElementTest',
+    'Drupal\locale\Tests\LocaleContentTest',
+    'Drupal\node\Tests\NodeFieldMultilingualTestCase',
+    'Drupal\node\Tests\NodeTypeInitialLanguageTest',
+    'Drupal\node\Tests\NodeTypePersistenceTest',
+    'Drupal\node\Tests\NodeTypeTest',
+    'Drupal\number\Tests\NumberFieldTest',
+    'Drupal\path\Tests\PathLanguageTest',
+    'Drupal\system\Tests\Entity\EntityTranslationFormTest',
+    'Drupal\translation\Tests\TranslationTest',
+  );
   return $test_list;
 }
 
