diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php
index 571b991425..eb96044167 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php
@@ -92,6 +92,9 @@ public static function create(ContainerInterface $container) {
   public function update(array &$sandbox, $entity_type_id, callable $callback = NULL) {
     $storage = $this->entityTypeManager->getStorage($entity_type_id);
     $sandbox_key = 'config_entity_updater:' . $entity_type_id;
+    if (isset($sandbox['config_entity_updater']) && $sandbox['config_entity_updater'] !== debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[0]) {
+      throw new \RuntimeException('\Drupal\Core\Config\Entity\ConfigEntityUpdater::update() can only be called once per update function');
+    }
     if (!isset($sandbox[$sandbox_key])) {
       $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
       if (!($entity_type instanceof ConfigEntityTypeInterface)) {
@@ -99,6 +102,9 @@ public function update(array &$sandbox, $entity_type_id, callable $callback = NU
       }
       $sandbox[$sandbox_key]['entities'] = $storage->getQuery()->accessCheck(FALSE)->execute();
       $sandbox[$sandbox_key]['count'] = count($sandbox[$sandbox_key]['entities']);
+      // Save the caller so we can determine that this is only called once per
+      // update.
+      $sandbox['config_entity_updater'] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[0];
     }
 
     // The default behaviour is to fix dependencies.
diff --git a/core/modules/system/system.post_update.php b/core/modules/system/system.post_update.php
index 114d289120..ed1be50001 100644
--- a/core/modules/system/system.post_update.php
+++ b/core/modules/system/system.post_update.php
@@ -150,9 +150,17 @@ function system_post_update_language_item_callback() {
 }
 
 /**
- * Update all entity displays that contain extra fields.
+ * Legacy update function.
  */
-function system_post_update_extra_fields(&$sandbox = NULL) {
+function system_post_update_extra_fields() {
+  // Replaced by system_post_update_extra_fields_form_display() and
+  // system_post_update_extra_fields_view_display().
+}
+
+/**
+ * Update all entity form displays that contain extra fields.
+ */
+function system_post_update_extra_fields_form_display(&$sandbox = NULL) {
   $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
   $entity_field_manager = \Drupal::service('entity_field.manager');
 
@@ -175,6 +183,33 @@ function system_post_update_extra_fields(&$sandbox = NULL) {
   };
 
   $config_entity_updater->update($sandbox, 'entity_form_display', $callback);
+}
+
+/**
+ * Update all entity view displays that contain extra fields.
+ */
+function system_post_update_extra_fields_view_display(&$sandbox = NULL) {
+  $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
+  $entity_field_manager = \Drupal::service('entity_field.manager');
+
+  $callback = function (EntityDisplayInterface $display) use ($entity_field_manager) {
+    $display_context = $display instanceof EntityViewDisplayInterface ? 'display' : 'form';
+    $extra_fields = $entity_field_manager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle());
+
+    // If any extra fields are used as a component, resave the display with the
+    // updated component information.
+    $needs_save = FALSE;
+    if (!empty($extra_fields[$display_context])) {
+      foreach ($extra_fields[$display_context] as $name => $extra_field) {
+        if ($component = $display->getComponent($name)) {
+          $display->setComponent($name, $component);
+          $needs_save = TRUE;
+        }
+      }
+    }
+    return $needs_save;
+  };
+
   $config_entity_updater->update($sandbox, 'entity_view_display', $callback);
 }
 
diff --git a/core/modules/text/text.post_update.php b/core/modules/text/text.post_update.php
index 5c98e26b00..e1be0b9dae 100644
--- a/core/modules/text/text.post_update.php
+++ b/core/modules/text/text.post_update.php
@@ -11,9 +11,17 @@
 use Drupal\text\Plugin\Field\FieldWidget\TextareaWithSummaryWidget;
 
 /**
- * Update text_with_summary fields and widgets to add summary required flags.
+ * Legacy update function.
  */
-function text_post_update_add_required_summary_flag(&$sandbox = NULL) {
+function text_post_update_add_required_summary_flag() {
+  // Replaced by text_post_update_add_required_summary_flag_form_display() and
+  // text_post_update_add_required_summary_flag_field_config().
+}
+
+/**
+ * Update text_with_summary widgets to add summary required flags.
+ */
+function text_post_update_add_required_summary_flag_form_display(&$sandbox = NULL) {
   $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
   /** @var \Drupal\Core\Field\WidgetPluginManager $field_widget_manager */
   $field_widget_manager = \Drupal::service('plugin.manager.field.widget');
@@ -36,6 +44,15 @@ function text_post_update_add_required_summary_flag(&$sandbox = NULL) {
     return $needs_save;
   };
 
+  $config_entity_updater->update($sandbox, 'entity_form_display', $widget_callback);
+}
+
+/**
+ * Update text_with_summary fields to add summary required flags.
+ */
+function text_post_update_add_required_summary_flag_field_config(&$sandbox = NULL) {
+  $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
+
   $field_callback = function (FieldConfigInterface $field) {
     if ($field->getType() !== 'text_with_summary') {
       return FALSE;
@@ -44,6 +61,5 @@ function text_post_update_add_required_summary_flag(&$sandbox = NULL) {
     return TRUE;
   };
 
-  $config_entity_updater->update($sandbox, 'entity_form_display', $widget_callback);
   $config_entity_updater->update($sandbox, 'field_config', $field_callback);
 }
diff --git a/core/tests/Drupal/KernelTests/Core/Config/Entity/ConfigEntityUpdaterTest.php b/core/tests/Drupal/KernelTests/Core/Config/Entity/ConfigEntityUpdaterTest.php
index f76578f99c..616867af58 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/Entity/ConfigEntityUpdaterTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/Entity/ConfigEntityUpdaterTest.php
@@ -52,7 +52,7 @@ public function testUpdate() {
 
     // This should run against the first 10 entities. The even numbered labels
     // will have been updated.
-    $updater->update($sandbox, 'config_test', $callback);
+    $this->callUpdate($updater, $sandbox, 'config_test', $callback);
     $entities = $storage->loadMultiple();
     $this->assertEquals('config_test_8 (updated)', $entities['config_test_8']->label());
     $this->assertEquals('config_test_9', $entities['config_test_9']->label());
@@ -63,7 +63,7 @@ public function testUpdate() {
     $this->assertEquals(10 / 15, $sandbox['#finished']);
 
     // Update the rest.
-    $updater->update($sandbox, 'config_test', $callback);
+    $this->callUpdate($updater, $sandbox, 'config_test', $callback);
     $entities = $storage->loadMultiple();
     $this->assertEquals('config_test_8 (updated)', $entities['config_test_8']->label());
     $this->assertEquals('config_test_9', $entities['config_test_9']->label());
@@ -73,6 +73,25 @@ public function testUpdate() {
     $this->assertCount(0, $sandbox['config_entity_updater:config_test']['entities']);
   }
 
+  /**
+   * Calls \Drupal\Core\Config\Entity\ConfigEntityUpdater::update().
+   *
+   * This methods helps the test get around the multiple update calls exception.
+   *
+   * @param \Drupal\Core\Config\Entity\ConfigEntityUpdater $updater
+   *   The config entity updater object.
+   * @param array $sandbox
+   *   The batch sandbox.
+   * @param string $entity_type_id
+   *   The entity type ID.
+   * @param callable|null $callback
+   *   (optional) A callback to determine if a configuration entity should be
+   *   saved.
+   */
+  protected function callUpdate(ConfigEntityUpdater $updater, array &$sandbox, $entity_type_id, callable $callback = NULL) {
+    $updater->update($sandbox, $entity_type_id, $callback);
+  }
+
   /**
    * @covers ::update
    */
@@ -94,7 +113,7 @@ public function testUpdateDefaultCallback() {
     \Drupal::state()->set('config_test_new_dependency', 'added_dependency');
 
     // This should run against the first 10 entities.
-    $updater->update($sandbox, 'config_test');
+    $this->callUpdate($updater, $sandbox, 'config_test');
     $entities = $storage->loadMultiple();
     $this->assertEquals(['added_dependency'], $entities['config_test_7']->getDependencies()['module']);
     $this->assertEquals(['added_dependency'], $entities['config_test_8']->getDependencies()['module']);
@@ -105,7 +124,7 @@ public function testUpdateDefaultCallback() {
     $this->assertEquals(9 / 15, $sandbox['#finished']);
 
     // Update the rest.
-    $updater->update($sandbox, 'config_test');
+    $this->callUpdate($updater, $sandbox, 'config_test');
     $entities = $storage->loadMultiple();
     $this->assertEquals(['added_dependency'], $entities['config_test_9']->getDependencies()['module']);
     $this->assertEquals(['added_dependency'], $entities['config_test_14']->getDependencies()['module']);
@@ -125,4 +144,16 @@ public function testUpdateException() {
     $updater->update($sandbox, 'entity_test_mul_changed');
   }
 
+  /**
+   * @covers ::update
+   */
+  public function testUpdateOncePerUpdateException() {
+    $this->expectException(\RuntimeException::class);
+    $this->expectExceptionMessage('\Drupal\Core\Config\Entity\ConfigEntityUpdater::update() can only be called once per update function');
+    $updater = $this->container->get('class_resolver')->getInstanceFromDefinition(ConfigEntityUpdater::class);
+    $sandbox = [];
+    $updater->update($sandbox, 'config_test');
+    $updater->update($sandbox, 'config_test');
+  }
+
 }
