From 03bd7fc75b824e3eceeb7172d8d79a42d9389b2b Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Thu, 1 Oct 2015 19:43:05 +0100
Subject: [PATCH] Issue #2172843 by fgm, marthinal, pfrenssen, amateescu,
 andypost, Wim Leers, stefan.r, pwieck, deepak_123: Remove ability to update
 entity bundle machine names

---
 .../Config/Entity/ConfigEntityBundleBase.php  |  61 ++++----
 .../Core/Entity/BundleEntityFormBase.php      |  41 +++++
 .../Entity/EntityBundleListenerInterface.php  |  16 +-
 core/lib/Drupal/Core/Entity/EntityManager.php |  25 ---
 .../Entity/Sql/SqlContentEntityStorage.php    |  34 ----
 core/lib/Drupal/Core/Entity/entity.api.php    |  30 +---
 .../Core/Field/Entity/BaseFieldOverride.php   |   5 +-
 .../lib/Drupal/Core/Field/FieldConfigBase.php |  16 +-
 .../Core/Field/FieldConfigInterface.php       |   9 --
 .../src/BlockContentTypeForm.php              |   9 +-
 core/modules/book/src/Tests/BookTest.php      |  93 -----------
 core/modules/field/field.module               |  24 ---
 core/modules/field/src/Entity/FieldConfig.php |   2 +-
 .../src/Tests/FieldAttachStorageTest.php      |  18 +--
 core/modules/field_ui/field_ui.module         |   9 --
 .../field_ui/src/Tests/EntityDisplayTest.php  |  41 +----
 .../field_ui/src/Tests/ManageFieldsTest.php   |  13 --
 core/modules/language/language.module         |   9 --
 .../LanguageConfigurationElementTest.php      |  32 ++--
 core/modules/node/src/NodeTypeForm.php        |  15 +-
 .../Tests/NodeTypeRenameConfigImportTest.php  | 145 ------------------
 core/modules/node/src/Tests/NodeTypeTest.php  |  10 +-
 core/modules/shortcut/src/ShortcutSetForm.php |   7 +-
 .../src/Tests/Entity/FieldSqlStorageTest.php  |  29 ----
 .../modules/entity_test/entity_test.module    |  20 ---
 .../taxonomy/src/Entity/Vocabulary.php        |  42 -----
 .../taxonomy/src/Tests/VocabularyCrudTest.php |  31 ----
 core/modules/taxonomy/src/VocabularyForm.php  |  16 +-
 28 files changed, 126 insertions(+), 676 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Entity/BundleEntityFormBase.php
 delete mode 100644 core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php

diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php
index b2fd1719e343..8e27aef731dd 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php
@@ -7,8 +7,7 @@
 
 namespace Drupal\Core\Config\Entity;
 
-use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Config\ConfigNameException;
 use Drupal\Core\Entity\EntityStorageInterface;
 
 /**
@@ -19,31 +18,6 @@
  */
 abstract class ConfigEntityBundleBase extends ConfigEntityBase {
 
-  /**
-   * Renames displays when a bundle is renamed.
-   */
-  protected function renameDisplays() {
-    // Rename entity displays.
-    if ($this->getOriginalId() !== $this->id()) {
-      foreach ($this->loadDisplays('entity_view_display') as $display) {
-        $new_id = $this->getEntityType()->getBundleOf() . '.' . $this->id() . '.' . $display->getMode();
-        $display->set('id', $new_id);
-        $display->setTargetBundle($this->id());
-        $display->save();
-      }
-    }
-
-    // Rename entity form displays.
-    if ($this->getOriginalId() !== $this->id()) {
-      foreach ($this->loadDisplays('entity_form_display') as $form_display) {
-        $new_id = $this->getEntityType()->getBundleOf() . '.' . $this->id() . '.' . $form_display->getMode();
-        $form_display->set('id', $new_id);
-        $form_display->setTargetBundle($this->id());
-        $form_display->save();
-      }
-    }
-  }
-
   /**
    * Deletes display if a bundle is deleted.
    */
@@ -80,12 +54,6 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
       }
       // Entity bundle field definitions may depend on bundle settings.
       $entity_manager->clearCachedFieldDefinitions();
-
-      if ($this->getOriginalId() != $this->id()) {
-        // If the entity was renamed, update the displays.
-        $this->renameDisplays();
-        $entity_manager->onBundleRename($this->getOriginalId(), $this->id(), $bundle_of);
-      }
     }
   }
 
@@ -101,6 +69,33 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti
     }
   }
 
+  /**
+   * Acts on an entity before the presave hook is invoked.
+   *
+   * Used before the entity is saved and before invoking the presave hook.
+   *
+   * Ensure that config entities which are bundles of other entities cannot have
+   * their ID changed.
+   *
+   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
+   *   The entity storage object.
+   *
+   * @throws \Drupal\Core\Config\ConfigNameException
+   *   Thrown when attempting to rename a bundle entity.
+   */
+  public function preSave(EntityStorageInterface $storage) {
+    parent::preSave($storage);
+
+    // Only handle renames, not creations.
+    if (!$this->isNew() && $this->getOriginalId() !== $this->id()) {
+      $bundle_type = $this->getEntityType();
+      $bundle_of = $bundle_type->getBundleOf();
+      if (!empty($bundle_of)) {
+        throw new ConfigNameException("The machine name of the '{$bundle_type->getLabel()}' bundle cannot be changed.");
+      }
+    }
+  }
+
   /**
    * Returns view or form displays for this bundle.
    *
diff --git a/core/lib/Drupal/Core/Entity/BundleEntityFormBase.php b/core/lib/Drupal/Core/Entity/BundleEntityFormBase.php
new file mode 100644
index 000000000000..88ad30cbd756
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/BundleEntityFormBase.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\BundleEntityFormBase.
+ */
+
+namespace Drupal\Core\Entity;
+
+/**
+ * Class BundleEntityFormBase is a base form for bundle config entities.
+ */
+class BundleEntityFormBase extends EntityForm {
+
+  /**
+   * Protects the bundle entity's ID property's form element against changes.
+   *
+   * This method is assumed to be called on a completely built entity form,
+   * including a form element for the bundle config entity's ID property.
+   *
+   * @param array $form
+   *   The completely built entity bundle form array.
+   *
+   * @return array
+   *   The updated entity bundle form array.
+   */
+  protected function protectBundleIdElement(array $form) {
+    $entity = $this->getEntity();
+    $id_key = $entity->getEntityType()->getKey('id');
+    assert('isset($form[$id_key])');
+    $element = &$form[$id_key];
+
+    // Make sure the element is not accidentally re-enabled if it has already
+    // been disabled.
+    if (empty($element['#disabled'])) {
+      $element['#disabled'] = !$entity->isNew();
+    }
+    return $form;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityBundleListenerInterface.php b/core/lib/Drupal/Core/Entity/EntityBundleListenerInterface.php
index cbe96b394933..f1ad9a973ede 100644
--- a/core/lib/Drupal/Core/Entity/EntityBundleListenerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityBundleListenerInterface.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Entity;
 
 /**
- * An interface for reacting to entity bundle creation, deletion, and renames.
+ * An interface for reacting to entity bundle creation and deletion.
  *
  * @todo Convert to Symfony events: https://www.drupal.org/node/2332935
  */
@@ -24,20 +24,6 @@ interface EntityBundleListenerInterface {
    */
   public function onBundleCreate($bundle, $entity_type_id);
 
-  /**
-   * Reacts to a bundle being renamed.
-   *
-   * This method runs before fields are updated with the new bundle name.
-   *
-   * @param string $bundle
-   *   The name of the bundle being renamed.
-   * @param string $bundle_new
-   *   The new name of the bundle.
-   * @param string $entity_type_id
-   *   The entity type to which the bundle is bound; e.g. 'node' or 'user'.
-   */
-  public function onBundleRename($bundle, $bundle_new, $entity_type_id);
-
   /**
    * Reacts to a bundle being deleted.
    *
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index e4e0f8daced7..f00fd2cf956e 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -1367,31 +1367,6 @@ public function onBundleCreate($bundle, $entity_type_id) {
     $this->moduleHandler->invokeAll('entity_bundle_create', array($entity_type_id, $bundle));
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function onBundleRename($bundle_old, $bundle_new, $entity_type_id) {
-    $this->clearCachedBundles();
-    // Notify the entity storage.
-    $storage = $this->getStorage($entity_type_id);
-    if ($storage instanceof EntityBundleListenerInterface) {
-      $storage->onBundleRename($bundle_old, $bundle_new, $entity_type_id);
-    }
-
-    // Rename existing base field bundle overrides.
-    $overrides = $this->getStorage('base_field_override')->loadByProperties(array('entity_type' => $entity_type_id, 'bundle' => $bundle_old));
-    foreach ($overrides as $override) {
-      $override->set('id', $entity_type_id . '.' . $bundle_new . '.' . $override->getName());
-      $override->set('bundle', $bundle_new);
-      $override->allowBundleRename();
-      $override->save();
-    }
-
-    // Invoke hook_entity_bundle_rename() hook.
-    $this->moduleHandler->invokeAll('entity_bundle_rename', array($entity_type_id, $bundle_old, $bundle_new));
-    $this->clearCachedFieldDefinitions();
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
index e1283be5c518..12184dffe4dd 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -1493,40 +1493,6 @@ public function onBundleCreate($bundle, $entity_type_id) { }
    */
   public function onBundleDelete($bundle, $entity_type_id) { }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function onBundleRename($bundle, $bundle_new, $entity_type_id) {
-    // The method runs before the field definitions are updated, so we use the
-    // old bundle name.
-    $field_definitions = $this->entityManager->getFieldDefinitions($this->entityTypeId, $bundle);
-    // We need to handle deleted fields too. For now, this only makes sense for
-    // configurable fields, so we use the specific API.
-    // @todo Use the unified store of deleted field definitions instead in
-    //   https://www.drupal.org/node/2282119
-    $field_definitions += entity_load_multiple_by_properties('field_config', array('entity_type' => $this->entityTypeId, 'bundle' => $bundle, 'deleted' => TRUE, 'include_deleted' => TRUE));
-    $table_mapping = $this->getTableMapping();
-
-    foreach ($field_definitions as $field_definition) {
-      $storage_definition = $field_definition->getFieldStorageDefinition();
-      if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) {
-        $is_deleted = $this->storageDefinitionIsDeleted($storage_definition);
-        $table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $is_deleted);
-        $revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $is_deleted);
-        $this->database->update($table_name)
-          ->fields(array('bundle' => $bundle_new))
-          ->condition('bundle', $bundle)
-          ->execute();
-        if ($this->entityType->isRevisionable()) {
-          $this->database->update($revision_name)
-            ->fields(array('bundle' => $bundle_new))
-            ->condition('bundle', $bundle)
-            ->execute();
-        }
-      }
-    }
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Entity/entity.api.php b/core/lib/Drupal/Core/Entity/entity.api.php
index 6bdde075e0a3..f6ac3841463a 100644
--- a/core/lib/Drupal/Core/Entity/entity.api.php
+++ b/core/lib/Drupal/Core/Entity/entity.api.php
@@ -139,8 +139,8 @@
  * - Field configuration preSave(): hook_field_storage_config_update_forbid()
  * - Node postSave(): hook_node_access_records() and
  *   hook_node_access_records_alter()
- * - Config entities that are acting as entity bundles, in postSave():
- *   hook_entity_bundle_create() or hook_entity_bundle_rename() as appropriate
+ * - Config entities that are acting as entity bundles in postSave():
+ *   hook_entity_bundle_create()
  * - Comment: hook_comment_publish() and hook_comment_unpublish() as
  *   appropriate.
  *
@@ -350,6 +350,7 @@
  *   'bundle_entity_type' on the \Drupal\node\Entity\Node class. Also, the
  *   bundle config entity type annotation must have a 'bundle_of' entry,
  *   giving the machine name of the entity type it is acting as a bundle for.
+ *   These machine names are considered permanent, they may not be renamed.
  * - Additional annotations can be seen on entity class examples such as
  *   \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
  *   (configuration). These annotations are documented on
@@ -740,31 +741,6 @@ function hook_entity_bundle_create($entity_type_id, $bundle) {
   \Drupal::service('router.builder')->setRebuildNeeded();
 }
 
-/**
- * Act on entity_bundle_rename().
- *
- * This hook is invoked after the operation has been performed.
- *
- * @param string $entity_type_id
- *   The entity type to which the bundle is bound.
- * @param string $bundle_old
- *   The previous name of the bundle.
- * @param string $bundle_new
- *   The new name of the bundle.
- *
- * @see entity_crud
- */
-function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) {
-  // Update the settings associated with the bundle in my_module.settings.
-  $config = \Drupal::config('my_module.settings');
-  $bundle_settings = $config->get('bundle_settings');
-  if (isset($bundle_settings[$entity_type_id][$bundle_old])) {
-    $bundle_settings[$entity_type_id][$bundle_new] = $bundle_settings[$entity_type_id][$bundle_old];
-    unset($bundle_settings[$entity_type_id][$bundle_old]);
-    $config->set('bundle_settings', $bundle_settings);
-  }
-}
-
 /**
  * Act on entity_bundle_delete().
  *
diff --git a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
index 751693dbaf35..4a4deb3c9ddf 100644
--- a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
+++ b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
@@ -163,8 +163,7 @@ protected function getBaseFieldDefinition() {
    * {@inheritdoc}
    *
    * @throws \Drupal\Core\Field\FieldException
-   *   If the bundle is being changed and
-   *   BaseFieldOverride::allowBundleRename() has not been called.
+   *   If the bundle is being changed.
    */
   public function preSave(EntityStorageInterface $storage) {
     // Filter out unknown settings and make sure all settings are present, so
@@ -189,7 +188,7 @@ public function preSave(EntityStorageInterface $storage) {
       if ($this->entity_type != $this->original->entity_type) {
         throw new FieldException("Cannot change the entity_type of an existing base field bundle override (entity type:{$this->entity_type}, bundle:{$this->original->bundle}, field name: {$this->field_name})");
       }
-      if ($this->bundle != $this->original->bundle && empty($this->bundleRenameAllowed)) {
+      if ($this->bundle != $this->original->bundle) {
         throw new FieldException("Cannot change the bundle of an existing base field bundle override (entity type:{$this->entity_type}, bundle:{$this->original->bundle}, field name: {$this->field_name})");
       }
       $previous_definition = $this->original;
diff --git a/core/lib/Drupal/Core/Field/FieldConfigBase.php b/core/lib/Drupal/Core/Field/FieldConfigBase.php
index da0bca8035f1..e9fbaca654fc 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigBase.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php
@@ -179,13 +179,6 @@ abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigIn
    */
   protected $itemDefinition;
 
-  /**
-   * Flag indicating whether the bundle name can be renamed or not.
-   *
-   * @var bool
-   */
-  protected $bundleRenameAllowed = FALSE;
-
   /**
    * Array of constraint options keyed by constraint plugin ID.
    *
@@ -456,7 +449,7 @@ public function __sleep() {
     // Only serialize necessary properties, excluding those that can be
     // recalculated.
     $properties = get_object_vars($this);
-    unset($properties['fieldStorage'], $properties['itemDefinition'], $properties['bundleRenameAllowed'], $properties['original']);
+    unset($properties['fieldStorage'], $properties['itemDefinition'], $properties['original']);
     return array_keys($properties);
   }
 
@@ -528,13 +521,6 @@ public function getItemDefinition() {
     return $this->itemDefinition;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function allowBundleRename() {
-    $this->bundleRenameAllowed = TRUE;
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Field/FieldConfigInterface.php b/core/lib/Drupal/Core/Field/FieldConfigInterface.php
index 8b3d21f43a99..ff8501f6a2e5 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigInterface.php
@@ -282,13 +282,4 @@ public function addConstraint($constraint_name, $options = NULL);
    */
   public function setConstraints(array $constraints);
 
-  /**
-   * Allows a bundle to be renamed.
-   *
-   * Renaming a bundle on the instance is allowed when an entity's bundle
-   * is renamed and when field_entity_bundle_rename() does internal
-   * housekeeping.
-   */
-  public function allowBundleRename();
-
 }
diff --git a/core/modules/block_content/src/BlockContentTypeForm.php b/core/modules/block_content/src/BlockContentTypeForm.php
index 74473cfcc912..9474ccc63c5a 100644
--- a/core/modules/block_content/src/BlockContentTypeForm.php
+++ b/core/modules/block_content/src/BlockContentTypeForm.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\block_content;
 
-use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\BundleEntityFormBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\language\Entity\ContentLanguageSettings;
@@ -15,7 +15,7 @@
 /**
  * Base form for category edit forms.
  */
-class BlockContentTypeForm extends EntityForm {
+class BlockContentTypeForm extends BundleEntityFormBase {
 
   /**
    * {@inheritdoc}
@@ -48,7 +48,6 @@ public function form(array $form, FormStateInterface $form_state) {
         'exists' => '\Drupal\block_content\Entity\BlockContentType::load',
       ),
       '#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
-      '#disabled' => !$block_type->isNew(),
     );
 
     $form['description'] = array(
@@ -62,7 +61,7 @@ public function form(array $form, FormStateInterface $form_state) {
       '#type' => 'checkbox',
       '#title' => t('Create new revision'),
       '#default_value' => $block_type->shouldCreateNewRevision(),
-      '#description' => t('Create a new revision by default for this block type.')
+      '#description' => t('Create a new revision by default for this block type.'),
     );
 
     if ($this->moduleHandler->moduleExists('language')) {
@@ -91,7 +90,7 @@ public function form(array $form, FormStateInterface $form_state) {
       '#value' => t('Save'),
     );
 
-    return $form;
+    return $this->protectBundleIdElement($form);
   }
 
   /**
diff --git a/core/modules/book/src/Tests/BookTest.php b/core/modules/book/src/Tests/BookTest.php
index 86c23be4d1a8..b1c9fa3f2893 100644
--- a/core/modules/book/src/Tests/BookTest.php
+++ b/core/modules/book/src/Tests/BookTest.php
@@ -497,99 +497,6 @@ function testBookDelete() {
      $this->assertTrue(empty($node->book), 'Deleting childless top-level book node properly allowed.');
    }
 
-  /*
-   * Tests node type changing machine name when type is a book allowed type.
-   */
-  function testBookNodeTypeChange() {
-    $this->drupalLogin($this->adminUser);
-    // Change the name, machine name and description.
-    $edit = array(
-      'name' => 'Bar',
-      'type' => 'bar',
-    );
-    $this->drupalPostForm('admin/structure/types/manage/book', $edit, t('Save content type'));
-
-    // Ensure that the config book.settings:allowed_types has been updated with
-    // the new machine and the old one has been removed.
-    $this->assertTrue(book_type_is_allowed('bar'), 'Config book.settings:allowed_types contains the updated node type machine name "bar".');
-    $this->assertFalse(book_type_is_allowed('book'), 'Config book.settings:allowed_types does not contain the old node type machine name "book".');
-
-    $edit = array(
-      'name' => 'Basic page',
-      'title_label' => 'Title for basic page',
-      'type' => 'page',
-    );
-    $this->drupalPostForm('admin/structure/types/add', $edit, t('Save content type'));
-
-    // Add page to the allowed node types.
-    $edit = array(
-      'book_allowed_types[page]' => 'page',
-      'book_allowed_types[bar]' => 'bar',
-    );
-
-    $this->drupalPostForm('admin/structure/book/settings', $edit, t('Save configuration'));
-    $this->assertTrue(book_type_is_allowed('bar'), 'Config book.settings:allowed_types contains the bar node type.');
-    $this->assertTrue(book_type_is_allowed('page'), 'Config book.settings:allowed_types contains the page node type.');
-
-    // Test the order of the book.settings::allowed_types configuration is as
-    // expected. The point of this test is to prove that after changing a node
-    // type going to admin/structure/book/settings and pressing save without
-    // changing anything should not alter the book.settings configuration. The
-    // order will be:
-    // @code
-    // array(
-    //   'bar',
-    //   'page',
-    // );
-    // @endcode
-    $current_config = $this->config('book.settings')->get();
-    $this->drupalPostForm('admin/structure/book/settings', array(), t('Save configuration'));
-    $this->assertIdentical($current_config, $this->config('book.settings')->get());
-
-    // Change the name, machine name and description.
-    $edit = array(
-      'name' => 'Zebra book',
-      'type' => 'zebra',
-    );
-    $this->drupalPostForm('admin/structure/types/manage/bar', $edit, t('Save content type'));
-    $this->assertTrue(book_type_is_allowed('zebra'), 'Config book.settings:allowed_types contains the zebra node type.');
-    $this->assertTrue(book_type_is_allowed('page'), 'Config book.settings:allowed_types contains the page node type.');
-
-    // Test the order of the book.settings::allowed_types configuration is as
-    // expected. The order should be:
-    // @code
-    // array(
-    //   'page',
-    //   'zebra',
-    // );
-    // @endcode
-    $current_config = $this->config('book.settings')->get();
-    $this->drupalPostForm('admin/structure/book/settings', array(), t('Save configuration'));
-    $this->assertIdentical($current_config, $this->config('book.settings')->get());
-
-    $edit = array(
-      'name' => 'Animal book',
-      'type' => 'zebra',
-    );
-    $this->drupalPostForm('admin/structure/types/manage/zebra', $edit, t('Save content type'));
-
-    // Test the order of the book.settings::allowed_types configuration is as
-    // expected. The order should be:
-    // @code
-    // array(
-    //   'page',
-    //   'zebra',
-    // );
-    // @endcode
-    $current_config = $this->config('book.settings')->get();
-    $this->drupalPostForm('admin/structure/book/settings', array(), t('Save configuration'));
-    $this->assertIdentical($current_config, $this->config('book.settings')->get());
-
-    // Ensure that after all the node type changes book.settings:child_type has
-    // the expected value.
-    $this->assertEqual($this->config('book.settings')->get('child_type'), 'zebra');
-  }
-
   /**
    * Tests re-ordering of books.
    */
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 64a24f6ceff7..666917cd0b24 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -186,30 +186,6 @@ function field_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundl
   }
 }
 
-/**
- * Implements hook_entity_bundle_rename().
- */
-function field_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
-  $fields = entity_load_multiple_by_properties('field_config', array('entity_type' => $entity_type, 'bundle' => $bundle_old, 'include_deleted' => TRUE));
-  foreach ($fields as $field) {
-    $id_new = $field->getTargetEntityTypeId() . '.' . $bundle_new . '.' . $field->getName();
-    $field->set('id', $id_new);
-    $field->set('bundle', $bundle_new);
-    // Save non-deleted fields.
-    if (!$field->isDeleted()) {
-      $field->allowBundleRename();
-      $field->save();
-    }
-    // Update deleted fields directly in the state storage.
-    else {
-      $state = \Drupal::state();
-      $deleted_fields = $state->get('field.field.deleted') ?: array();
-      $deleted_fields[$field->uuid] = $field->toArray();
-      $state->set('field.field.deleted', $deleted_fields);
-    }
-  }
-}
-
 /**
  * Implements hook_entity_bundle_delete().
  *
diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php
index a889803b480f..1493e41fcd71 100644
--- a/core/modules/field/src/Entity/FieldConfig.php
+++ b/core/modules/field/src/Entity/FieldConfig.php
@@ -167,7 +167,7 @@ public function preSave(EntityStorageInterface $storage) {
       if ($this->entity_type != $this->original->entity_type) {
         throw new FieldException("Cannot change an existing field's entity_type.");
       }
-      if ($this->bundle != $this->original->bundle && empty($this->bundleRenameAllowed)) {
+      if ($this->bundle != $this->original->bundle) {
         throw new FieldException("Cannot change an existing field's bundle.");
       }
       if ($storage_definition->uuid() != $this->original->getFieldStorageDefinition()->uuid()) {
diff --git a/core/modules/field/src/Tests/FieldAttachStorageTest.php b/core/modules/field/src/Tests/FieldAttachStorageTest.php
index 77c7bacfe9a0..a7c72178e871 100644
--- a/core/modules/field/src/Tests/FieldAttachStorageTest.php
+++ b/core/modules/field/src/Tests/FieldAttachStorageTest.php
@@ -275,9 +275,9 @@ function testFieldAttachDelete() {
   }
 
   /**
-   * Test entity_bundle_create() and entity_bundle_rename().
+   * Test entity_bundle_create().
    */
-  function testEntityCreateRenameBundle() {
+  function testEntityCreateBundle() {
     $entity_type = 'entity_test_rev';
     $this->createFieldWithStorage('', $entity_type);
     $cardinality = $this->fieldTestData->field_storage->getCardinality();
@@ -298,20 +298,6 @@ function testEntityCreateRenameBundle() {
     // Verify the field data is present on load.
     $entity = $this->entitySaveReload($entity);
     $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, "Data is retrieved for the new bundle");
-
-    // Rename the bundle.
-    $new_bundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName());
-    entity_test_rename_bundle($this->fieldTestData->field_definition['bundle'], $new_bundle, $entity_type);
-
-    // Check that the field definition has been updated.
-    $this->fieldTestData->field = FieldConfig::loadByName($entity_type, $new_bundle, $this->fieldTestData->field_name);
-    $this->assertIdentical($this->fieldTestData->field->getTargetBundle(), $new_bundle, "Bundle name has been updated in the field.");
-
-    // Verify the field data is present on load.
-    $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId());
-    $controller->resetCache();
-    $entity = $controller->load($entity->id());
-    $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, "Bundle name has been updated in the field storage");
   }
 
   /**
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 2193bc4d1093..3008b3763376 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -107,15 +107,6 @@ function field_ui_entity_bundle_create($entity_type, $bundle) {
   \Drupal::service('router.builder')->setRebuildNeeded();
 }
 
-/**
- * Implements hook_entity_bundle_rename().
- */
-function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
-  // When a bundle is renamed, the menu needs to be rebuilt to add our
-  // menu item tabs.
-  \Drupal::service('router.builder')->setRebuildNeeded();
-}
-
 /**
  * Implements hook_form_FORM_ID_alter().
  *
diff --git a/core/modules/field_ui/src/Tests/EntityDisplayTest.php b/core/modules/field_ui/src/Tests/EntityDisplayTest.php
index 53a8639fba68..abb16eb282b9 100644
--- a/core/modules/field_ui/src/Tests/EntityDisplayTest.php
+++ b/core/modules/field_ui/src/Tests/EntityDisplayTest.php
@@ -300,9 +300,9 @@ public function testBaseFieldComponent() {
   }
 
   /**
-   * Tests renaming and deleting a bundle.
+   * Tests deleting a bundle.
    */
-  public function testRenameDeleteBundle() {
+  public function testDeleteBundle() {
     // Create a node bundle, display and form display object.
     $type = NodeType::create(array('type' => 'article'));
     $type->save();
@@ -310,44 +310,11 @@ public function testRenameDeleteBundle() {
     entity_get_display('node', 'article', 'default')->save();
     entity_get_form_display('node', 'article', 'default')->save();
 
-    // Rename the article bundle and assert the entity display is renamed.
-    $type->old_type = 'article';
-    $type->set('type', 'article_rename');
-    $type->save();
-    $old_display = entity_load('entity_view_display', 'node.article.default');
-    $this->assertFalse((bool) $old_display);
-    $old_form_display = entity_load('entity_form_display', 'node.article.default');
-    $this->assertFalse((bool) $old_form_display);
-    $new_display = entity_load('entity_view_display', 'node.article_rename.default');
-    $this->assertEqual('article_rename', $new_display->getTargetBundle());
-    $this->assertEqual('node.article_rename.default', $new_display->id());
-    $new_form_display = entity_load('entity_form_display', 'node.article_rename.default');
-    $this->assertEqual('article_rename', $new_form_display->getTargetBundle());
-    $this->assertEqual('node.article_rename.default', $new_form_display->id());
-
-    $expected_view_dependencies = array(
-      'config' => array('field.field.node.article_rename.body', 'node.type.article_rename'),
-      'module' => array('entity_test', 'text', 'user')
-    );
-    // Check that the display has dependencies on the bundle, fields and the
-    // modules that provide the formatters.
-    $dependencies = $new_display->calculateDependencies();
-    $this->assertEqual($expected_view_dependencies, $dependencies);
-
-    // Check that the form display has dependencies on the bundle, fields and
-    // the modules that provide the formatters.
-    $dependencies = $new_form_display->calculateDependencies();
-    $expected_form_dependencies = array(
-      'config' => array('field.field.node.article_rename.body', 'node.type.article_rename'),
-      'module' => array('text')
-    );
-    $this->assertEqual($expected_form_dependencies, $dependencies);
-
     // Delete the bundle.
     $type->delete();
-    $display = entity_load('entity_view_display', 'node.article_rename.default');
+    $display = entity_load('entity_view_display', 'node.article.default');
     $this->assertFalse((bool) $display);
-    $form_display = entity_load('entity_form_display', 'node.article_rename.default');
+    $form_display = entity_load('entity_form_display', 'node.article.default');
     $this->assertFalse((bool) $form_display);
   }
 
diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php
index e4e99813a8e5..48ae2a241ee5 100644
--- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php
+++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php
@@ -590,19 +590,6 @@ function testHiddenFields() {
     }
   }
 
-  /**
-   * Tests renaming a bundle.
-   */
-  function testRenameBundle() {
-    $type2 = strtolower($this->randomMachineName(8)) . '_test';
-
-    $options = array(
-      'type' => $type2,
-    );
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->contentType, $options, t('Save content type'));
-    $this->manageFieldsPage($type2);
-  }
-
   /**
    * Tests that a duplicate field name is caught by validation.
    */
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 34a433aa599e..30fedc6e3b68 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -217,15 +217,6 @@ function language_configuration_element_submit(&$form, FormStateInterface $form_
   }
 }
 
-/**
- * Implements hook_entity_bundle_rename().
- */
-function language_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) {
-  ContentLanguageSettings::loadByEntityTypeBundle($entity_type_id, $bundle_old)
-    ->setTargetBundle($bundle_new)
-    ->save();
-}
-
 /**
  * Implements hook_entity_bundle_delete().
  */
diff --git a/core/modules/language/src/Tests/LanguageConfigurationElementTest.php b/core/modules/language/src/Tests/LanguageConfigurationElementTest.php
index a8f33aa2d45d..9591618fc39c 100644
--- a/core/modules/language/src/Tests/LanguageConfigurationElementTest.php
+++ b/core/modules/language/src/Tests/LanguageConfigurationElementTest.php
@@ -152,7 +152,7 @@ public function testDefaultLangcode() {
   }
 
   /**
-   * Tests that the configuration is updated when the node type is changed.
+   * Tests that the configuration is retained when the node type is updated.
    */
   public function testNodeTypeUpdate() {
     // Create the article content type first if the profile used is not the
@@ -172,16 +172,16 @@ public function testNodeTypeUpdate() {
     $uuid = $configuration->uuid();
     $this->assertEqual($configuration->getDefaultLangcode(), 'current_interface', 'The default language configuration has been saved on the Article content type.');
     $this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been saved on the Article content type.');
-    // Rename the article content type.
+    // Update the article content type by changing the title label.
     $edit = array(
-      'type' => 'article_2'
+      'title_label' => 'Name'
     );
     $this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type'));
-    // Check that we still have the settings for the new node type.
-    $configuration = ContentLanguageSettings::loadByEntityTypeBundle('node', 'article_2');
-    $this->assertEqual($configuration->getDefaultLangcode(), 'current_interface', 'The default language configuration has been kept on the new Article content type.');
-    $this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been kept on the new Article content type.');
-    $this->assertEqual($configuration->uuid(), $uuid, 'The language configuration uuid has been kept on the new Article content type.');
+    // Check that we still have the settings for the updated node type.
+    $configuration = ContentLanguageSettings::loadByEntityTypeBundle('node', 'article');
+    $this->assertEqual($configuration->getDefaultLangcode(), 'current_interface', 'The default language configuration has been kept on the updated Article content type.');
+    $this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been kept on the updated Article content type.');
+    $this->assertEqual($configuration->uuid(), $uuid, 'The language configuration uuid has been kept on the updated Article content type.');
   }
 
   /**
@@ -220,7 +220,7 @@ public function testNodeTypeDelete() {
   }
 
   /**
-   * Tests that the configuration is updated when a vocabulary is changed.
+   * Tests that the configuration is retained when a vocabulary is updated.
    */
   public function testTaxonomyVocabularyUpdate() {
     $vocabulary = entity_create('taxonomy_vocabulary', array(
@@ -242,16 +242,16 @@ public function testTaxonomyVocabularyUpdate() {
     $uuid = $configuration->uuid();
     $this->assertEqual($configuration->getDefaultLangcode(), 'current_interface', 'The default language configuration has been saved on the Country vocabulary.');
     $this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been saved on the Country vocabulary.');
-    // Rename the vocabulary.
+    // Update the vocabulary.
     $edit = array(
-      'vid' => 'nation'
+      'name' => 'Nation'
     );
     $this->drupalPostForm('admin/structure/taxonomy/manage/country', $edit, t('Save'));
-    // Check that we still have the settings for the new vocabulary.
-    $configuration = ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', 'nation');
-    $this->assertEqual($configuration->getDefaultLangcode(), 'current_interface', 'The default language configuration has been kept on the new Country vocabulary.');
-    $this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been kept on the new Country vocabulary.');
-    $this->assertEqual($configuration->uuid(), $uuid, 'The language configuration uuid has been kept on the new Country vocabulary.');
+    // Check that we still have the settings for the updated vocabulary.
+    $configuration = ContentLanguageSettings::loadByEntityTypeBundle('taxonomy_term', 'country');
+    $this->assertEqual($configuration->getDefaultLangcode(), 'current_interface', 'The default language configuration has been kept on the updated Country vocabulary.');
+    $this->assertTrue($configuration->isLanguageAlterable(), 'The alterable language configuration has been kept on the updated Country vocabulary.');
+    $this->assertEqual($configuration->uuid(), $uuid, 'The language configuration uuid has been kept on the updated Country vocabulary.');
   }
 
 }
diff --git a/core/modules/node/src/NodeTypeForm.php b/core/modules/node/src/NodeTypeForm.php
index 1c1a5884d69c..e4f8cf570ac4 100644
--- a/core/modules/node/src/NodeTypeForm.php
+++ b/core/modules/node/src/NodeTypeForm.php
@@ -7,18 +7,17 @@
 
 namespace Drupal\node;
 
-use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\BundleEntityFormBase;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
 use Drupal\language\Entity\ContentLanguageSettings;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Form controller for node type forms.
  */
-class NodeTypeForm extends EntityForm {
+class NodeTypeForm extends BundleEntityFormBase {
 
   /**
    * The entity manager.
@@ -31,7 +30,7 @@ class NodeTypeForm extends EntityForm {
    * Constructs the NodeTypeForm object.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager
+   *   The entity manager.
    */
   public function __construct(EntityManagerInterface $entity_manager) {
     $this->entityManager = $entity_manager;
@@ -148,7 +147,8 @@ public function form(array $form, FormStateInterface $form_state) {
     // Prepare workflow options to be used for 'checkboxes' form element.
     $keys = array_keys(array_filter($workflow_options));
     $workflow_options = array_combine($keys, $keys);
-    $form['workflow']['options'] = array('#type' => 'checkboxes',
+    $form['workflow']['options'] = array(
+      '#type' => 'checkboxes',
       '#title' => t('Default options'),
       '#default_value' => $workflow_options,
       '#options' => array(
@@ -187,7 +187,8 @@ public function form(array $form, FormStateInterface $form_state) {
       '#default_value' => $type->displaySubmitted(),
       '#description' => t('Author username and publish date will be displayed.'),
     );
-    return $form;
+
+    return $this->protectBundleIdElement($form);
   }
 
   /**
@@ -247,7 +248,7 @@ public function save(array $form, FormStateInterface $form_state) {
     // @todo Make it possible to get default values without an entity.
     //   https://www.drupal.org/node/2318187
     $node = $this->entityManager->getStorage('node')->create(array('type' => $type->id()));
-    foreach (array('status', 'promote', 'sticky')  as $field_name) {
+    foreach (array('status', 'promote', 'sticky') as $field_name) {
       $value = (bool) $form_state->getValue(['options', $field_name]);
       if ($node->$field_name->value != $value) {
         $fields[$field_name]->getConfig($type->id())->setDefaultValue($value)->save();
diff --git a/core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php b/core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php
deleted file mode 100644
index 75e4f0da7c75..000000000000
--- a/core/modules/node/src/Tests/NodeTypeRenameConfigImportTest.php
+++ /dev/null
@@ -1,145 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Tests\NodeTypeRenameConfigImportTest.
- */
-
-namespace Drupal\node\Tests;
-
-use Drupal\Component\Utility\SafeMarkup;
-use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Config\Entity\ConfigEntityStorage;
-use Drupal\simpletest\WebTestBase;
-use Drupal\node\Entity\NodeType;
-
-/**
- * Tests importing renamed node type via configuration synchronization.
- *
- * @group node
- */
-class NodeTypeRenameConfigImportTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('node', 'text', 'config');
-
-  /**
-   * A normal logged in user.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $webUser;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->webUser = $this->drupalCreateUser(array('synchronize configuration'));
-    $this->drupalLogin($this->webUser);
-  }
-
-  /**
-   * Tests configuration renaming.
-   */
-  public function testConfigurationRename() {
-    $content_type = $this->drupalCreateContentType(array(
-      'type' => Unicode::strtolower($this->randomMachineName(16)),
-      'name' => $this->randomMachineName(),
-    ));
-    $staged_type = $content_type->id();
-
-    // Check the default status value for a node of this type.
-    $node = entity_create('node', array('type' => $staged_type));
-    $this->assertTrue($node->status->value, 'Node status defaults to TRUE.');
-
-    // Override a core base field.
-    $fields = \Drupal::entityManager()->getFieldDefinitions($content_type->getEntityType()->getBundleOf(), $content_type->id());
-    $fields['status']->getConfig($content_type->id())->setDefaultValue(FALSE)->save();
-
-    $active = $this->container->get('config.storage');
-    $staging = $this->container->get('config.storage.staging');
-
-    $config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id();
-    // Emulate a staging operation.
-    $this->copyConfig($active, $staging);
-
-    // Change the machine name of the content type.
-    $content_type->set('type', Unicode::strtolower($this->randomMachineName(8)));
-    $content_type->save();
-    $active_type = $content_type->id();
-
-    // Ensure the base field override has been renamed and the value is correct.
-    $node = entity_create('node', array('type' => $active_type));
-    $this->assertFalse($node->status->value, 'Node status defaults to FALSE.');
-
-    $renamed_config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id();
-    $this->assertTrue($active->exists($renamed_config_name), 'The content type has the new name in the active store.');
-    $this->assertFalse($active->exists($config_name), "The content type's old name does not exist active store.");
-
-    $this->configImporter()->reset();
-    $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('create')), 'There are no configuration items to create.');
-    $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('delete')), 'There are no configuration items to delete.');
-    $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('update')), 'There are no configuration items to update.');
-
-    // We expect that changing the machine name of the content type will
-    // rename five configuration entities: the node type, the body field
-    // instance, two entity form displays, and the entity view display.
-    // @see \Drupal\node\Entity\NodeType::postSave()
-    $expected = array(
-      'node.type.' . $active_type . '::node.type.' . $staged_type,
-      'core.base_field_override.node.' . $active_type . '.status::core.base_field_override.node.' . $staged_type . '.status',
-      'core.entity_form_display.node.' . $active_type . '.default::core.entity_form_display.node.' . $staged_type . '.default',
-      'core.entity_view_display.node.' . $active_type . '.default::core.entity_view_display.node.' . $staged_type . '.default',
-      'core.entity_view_display.node.' . $active_type . '.teaser::core.entity_view_display.node.' . $staged_type . '.teaser',
-      'field.field.node.' . $active_type . '.body::field.field.node.' . $staged_type . '.body',
-    );
-    $renames = $this->configImporter()->getUnprocessedConfiguration('rename');
-    $this->assertIdentical($expected, $renames);
-
-    $this->drupalGet('admin/config/development/configuration');
-    foreach ($expected as $rename) {
-      $names = $this->configImporter()->getStorageComparer()->extractRenameNames($rename);
-      $this->assertText(SafeMarkup::format('@source_name to @target_name', array('@source_name' => $names['old_name'], '@target_name' => $names['new_name'])));
-      // Test that the diff link is present for each renamed item.
-      $href = \Drupal::urlGenerator()->getPathFromRoute('config.diff', array('source_name' => $names['old_name'], 'target_name' => $names['new_name']));
-      $this->assertLinkByHref($href);
-      $hrefs[$rename] = $href;
-    }
-
-    // Ensure that the diff works for each renamed item.
-    foreach ($hrefs as $rename => $href) {
-      $this->drupalGet($href);
-      $names = $this->configImporter()->getStorageComparer()->extractRenameNames($rename);
-      $config_entity_type = \Drupal::service('config.manager')->getEntityTypeIdByName($names['old_name']);
-      $entity_type = \Drupal::entityManager()->getDefinition($config_entity_type);
-      $old_id = ConfigEntityStorage::getIDFromConfigName($names['old_name'], $entity_type->getConfigPrefix());
-      $new_id = ConfigEntityStorage::getIDFromConfigName($names['new_name'], $entity_type->getConfigPrefix());
-
-      // Because table columns can be on multiple lines, need to assert a regex
-      // pattern rather than normal text.
-      $id_key = $entity_type->getKey('id');
-      $text = "$id_key: $old_id";
-      $this->assertTextPattern('/\-\s+' . preg_quote($text, '/') . '/', "'-$text' found.");
-      $text = "$id_key: $new_id";
-      $this->assertTextPattern('/\+\s+' . preg_quote($text, '/') . '/', "'+$text' found.");
-    }
-
-    // Run the import.
-    $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all'));
-    $this->assertText(t('There are no configuration changes to import.'));
-
-    $this->assertFalse(NodeType::load($active_type), 'The content no longer exists with the old name.');
-    $content_type = NodeType::load($staged_type);
-    $this->assertIdentical($staged_type, $content_type->id());
-
-    // Ensure the base field override has been renamed and the value is correct.
-    $node = entity_create('node', array('type' => $staged_type));
-    $this->assertFALSE($node->status->value, 'Node status defaults to FALSE.');
-  }
-
-}
diff --git a/core/modules/node/src/Tests/NodeTypeTest.php b/core/modules/node/src/Tests/NodeTypeTest.php
index 11d939a4f58d..c30b424daf95 100644
--- a/core/modules/node/src/Tests/NodeTypeTest.php
+++ b/core/modules/node/src/Tests/NodeTypeTest.php
@@ -99,10 +99,9 @@ function testNodeTypeEditing() {
     $this->assertRaw('Foo', 'New title label was displayed.');
     $this->assertNoRaw('Title', 'Old title label was not displayed.');
 
-    // Change the name, machine name and description.
+    // Change the name and the description.
     $edit = array(
       'name' => 'Bar',
-      'type' => 'bar',
       'description' => 'Lorem ipsum.',
     );
     $this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
@@ -111,16 +110,15 @@ function testNodeTypeEditing() {
     $this->assertRaw('Bar', 'New name was displayed.');
     $this->assertRaw('Lorem ipsum', 'New description was displayed.');
     $this->clickLink('Bar');
-    $this->assertUrl(\Drupal::url('node.add', ['node_type' => 'bar'], ['absolute' => TRUE]), [], 'New machine name was used in URL.');
     $this->assertRaw('Foo', 'Title field was found.');
     $this->assertRaw('Body', 'Body field was found.');
 
     // Remove the body field.
-    $this->drupalPostForm('admin/structure/types/manage/bar/fields/node.bar.body/delete', array(), t('Delete'));
+    $this->drupalPostForm('admin/structure/types/manage/page/fields/node.page.body/delete', array(), t('Delete'));
     // Resave the settings for this type.
-    $this->drupalPostForm('admin/structure/types/manage/bar', array(), t('Save content type'));
+    $this->drupalPostForm('admin/structure/types/manage/page', array(), t('Save content type'));
     // Check that the body field doesn't exist.
-    $this->drupalGet('node/add/bar');
+    $this->drupalGet('node/add/page');
     $this->assertNoRaw('Body', 'Body field was not found.');
   }
 
diff --git a/core/modules/shortcut/src/ShortcutSetForm.php b/core/modules/shortcut/src/ShortcutSetForm.php
index 9708aee611d4..fd21f7c77624 100644
--- a/core/modules/shortcut/src/ShortcutSetForm.php
+++ b/core/modules/shortcut/src/ShortcutSetForm.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\shortcut;
 
-use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\BundleEntityFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for the shortcut set entity edit forms.
  */
-class ShortcutSetForm extends EntityForm {
+class ShortcutSetForm extends BundleEntityFormBase {
 
   /**
    * {@inheritdoc}
@@ -38,14 +38,13 @@ public function form(array $form, FormStateInterface $form_state) {
         'replace' => '-',
       ),
       '#default_value' => $entity->id(),
-      '#disabled' => !$entity->isNew(),
       // This id could be used for menu name.
       '#maxlength' => 23,
     );
 
     $form['actions']['submit']['#value'] = t('Create new set');
 
-    return $form;
+    return $this->protectBundleIdElement($form);
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Entity/FieldSqlStorageTest.php b/core/modules/system/src/Tests/Entity/FieldSqlStorageTest.php
index 549c17ae9f94..67b0e9490a35 100644
--- a/core/modules/system/src/Tests/Entity/FieldSqlStorageTest.php
+++ b/core/modules/system/src/Tests/Entity/FieldSqlStorageTest.php
@@ -469,35 +469,6 @@ function testFieldSqlStorageForeignKeys() {
     $this->assertEqual($schema['foreign keys'][$foreign_key_name]['columns'][$foreign_key_name], 'id', 'Foreign key column name modified after update');
   }
 
-  /**
-   * Tests reacting to a bundle being renamed.
-   */
-  function testFieldSqlStorageBundleRename() {
-    $entity_type = $bundle = 'entity_test_rev';
-    $field_name = $this->fieldStorage->getName();
-
-    // Create an entity.
-    $value = mt_rand(1, 127);
-    $entity = entity_create($entity_type, array(
-      'type' => $bundle,
-      $field_name => $value,
-    ));
-    $entity->save();
-
-    // Rename the bundle.
-    $bundle_new = $bundle . '_renamed';
-    entity_test_rename_bundle($bundle, $bundle_new, $entity_type);
-
-    // Check that the 'bundle' column has been updated in storage.
-    $row = db_select($this->table, 't')
-      ->fields('t', array('bundle', $field_name . '_value'))
-      ->condition('entity_id', $entity->id())
-      ->execute()
-      ->fetch();
-    $this->assertEqual($row->bundle, $bundle_new);
-    $this->assertEqual($row->{$field_name . '_value'}, $value);
-  }
-
   /**
    * Tests table name generation.
    */
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index eea78e82a4ed..101a466e1de7 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -170,26 +170,6 @@ function entity_test_create_bundle($bundle, $text = NULL, $entity_type = 'entity
   \Drupal::entityManager()->onBundleCreate($bundle, $entity_type);
 }
 
-/**
- * Renames a bundle for entity_test entities.
- *
- * @param string $bundle_old
- *   The machine-readable name of the bundle to rename.
- * @param string $bundle_new
- *   The new machine-readable name of the bundle.
- * @param string $entity_type
- *   (optional) The entity type for which the bundle is renamed. Defaults to
- *   'entity_test'.
- */
-function entity_test_rename_bundle($bundle_old, $bundle_new, $entity_type = 'entity_test') {
-  $bundles = \Drupal::state()->get($entity_type . '.bundles') ?: array($entity_type => array('label' => 'Entity Test Bundle'));
-  $bundles[$bundle_new] = $bundles[$bundle_old];
-  unset($bundles[$bundle_old]);
-  \Drupal::state()->set($entity_type . '.bundles', $bundles);
-
-  \Drupal::entityManager()->onBundleRename($bundle_old, $bundle_new, $entity_type);
-}
-
 /**
  * Deletes a bundle for entity_test entities.
  *
diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php
index 2855c6596c51..c8cc1c0e96a6 100644
--- a/core/modules/taxonomy/src/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/src/Entity/Vocabulary.php
@@ -122,48 +122,6 @@ public function getDescription() {
     return $this->description;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
-    parent::postSave($storage, $update);
-
-    if ($update && $this->getOriginalId() != $this->id() && !$this->isSyncing()) {
-      // Reflect machine name changes in the definitions of existing 'taxonomy'
-      // fields.
-      $field_ids = array();
-      $field_map = \Drupal::entityManager()->getFieldMapByFieldType('entity_reference');
-      foreach ($field_map as $entity_type => $field_storages) {
-        foreach ($field_storages as $field_storage => $info) {
-          $field_ids[] = $entity_type . '.' . $field_storage;
-        }
-      }
-
-      $field_storages = \Drupal::entityManager()->getStorage('field_storage_config')->loadMultiple($field_ids);
-      $taxonomy_fields = array_filter($field_storages, function ($field_storage) {
-        return $field_storage->getType() == 'entity_reference' && $field_storage->getSetting('target_type') == 'taxonomy_term';
-      });
-
-      foreach ($taxonomy_fields as $field_storage) {
-        $update_storage = FALSE;
-
-        $allowed_values = $field_storage->getSetting('allowed_values');
-        foreach ($allowed_values as &$value) {
-          if ($value['vocabulary'] == $this->getOriginalId()) {
-            $value['vocabulary'] = $this->id();
-            $update_storage = TRUE;
-          }
-        }
-        $field_storage->setSetting('allowed_values', $allowed_values);
-
-        if ($update_storage) {
-          $field_storage->save();
-        }
-      }
-    }
-    $storage->resetCache($update ? array($this->getOriginalId()) : array());
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/taxonomy/src/Tests/VocabularyCrudTest.php b/core/modules/taxonomy/src/Tests/VocabularyCrudTest.php
index 1c174d4b62ee..a46a47e541fc 100644
--- a/core/modules/taxonomy/src/Tests/VocabularyCrudTest.php
+++ b/core/modules/taxonomy/src/Tests/VocabularyCrudTest.php
@@ -142,37 +142,6 @@ function testTaxonomyVocabularyLoadMultiple() {
     $this->assertEqual($vocabulary->id(), $vocabulary2->id(), 'Vocabulary loaded successfully by name and ID.');
   }
 
-  /**
-   * Tests that machine name changes are properly reflected.
-   */
-  function testTaxonomyVocabularyChangeMachineName() {
-    // Add a field to the vocabulary.
-    entity_create('field_storage_config', array(
-      'field_name' => 'field_test',
-      'entity_type' => 'taxonomy_term',
-      'type' => 'test_field',
-    ))->save();
-    entity_create('field_config', array(
-      'field_name' => 'field_test',
-      'entity_type' => 'taxonomy_term',
-      'bundle' => $this->vocabulary->id(),
-    ))->save();
-
-    // Change the machine name.
-    $old_name = $this->vocabulary->id();
-    $new_name = Unicode::strtolower($this->randomMachineName());
-    $this->vocabulary->set('vid', $new_name);
-    $this->vocabulary->save();
-
-    // Check that entity bundles are properly updated.
-    $info = entity_get_bundles('taxonomy_term');
-    $this->assertFalse(isset($info[$old_name]), 'The old bundle name does not appear in entity_get_bundles().');
-    $this->assertTrue(isset($info[$new_name]), 'The new bundle name appears in entity_get_bundles().');
-
-    // Check that the field is still attached to the vocabulary.
-    $this->assertTrue(FieldConfig::loadByName('taxonomy_term', $new_name, 'field_test'), 'The bundle name was updated correctly.');
-  }
-
   /**
    * Test uninstall and reinstall of the taxonomy module.
    */
diff --git a/core/modules/taxonomy/src/VocabularyForm.php b/core/modules/taxonomy/src/VocabularyForm.php
index dd2c1d82f451..e175af70c5ad 100644
--- a/core/modules/taxonomy/src/VocabularyForm.php
+++ b/core/modules/taxonomy/src/VocabularyForm.php
@@ -7,18 +7,17 @@
 
 namespace Drupal\taxonomy;
 
-use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\BundleEntityFormBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\language\Entity\ContentLanguageSettings;
-use Drupal\taxonomy\VocabularyStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Base form for vocabulary edit forms.
  */
-class VocabularyForm extends EntityForm {
+class VocabularyForm extends BundleEntityFormBase {
 
   /**
    * The vocabulary storage.
@@ -112,7 +111,8 @@ public function form(array $form, FormStateInterface $form_state) {
       '#value' => '0',
     );
 
-    return parent::form($form, $form_state, $vocabulary);
+    $form = parent::form($form, $form_state);
+    return $this->protectBundleIdElement($form);
   }
 
   /**
@@ -147,14 +147,14 @@ public function save(array $form, FormStateInterface $form_state) {
   /**
    * Determines if the vocabulary already exists.
    *
-   * @param string $id
-   *   The vocabulary ID
+   * @param string $vid
+   *   The vocabulary ID.
    *
    * @return bool
    *   TRUE if the vocabulary exists, FALSE otherwise.
    */
-  public function exists($id) {
-    $action = $this->vocabularyStorage->load($id);
+  public function exists($vid) {
+    $action = $this->vocabularyStorage->load($vid);
     return !empty($action);
   }
 
-- 
GitLab