diff --git a/core/modules/block_content/block_content.module b/core/modules/block_content/block_content.module
index 3adc979d9f..c8cbb23641 100644
--- a/core/modules/block_content/block_content.module
+++ b/core/modules/block_content/block_content.module
@@ -83,7 +83,10 @@ function block_content_add_body_field($block_type_id, $label = 'Body') {
       'field_storage' => FieldStorageConfig::loadByName('block_content', 'body'),
       'bundle' => $block_type_id,
       'label' => $label,
-      'settings' => ['display_summary' => FALSE],
+      'settings' => [
+        'display_summary' => FALSE,
+        'allowed_formats' => [],
+      ],
     ]);
     $field->save();
 
diff --git a/core/modules/block_content/migrations/block_content_body_field.yml b/core/modules/block_content/migrations/block_content_body_field.yml
index 9ed884f99e..bc30e0ff98 100644
--- a/core/modules/block_content/migrations/block_content_body_field.yml
+++ b/core/modules/block_content/migrations/block_content_body_field.yml
@@ -13,6 +13,7 @@ source:
       field_name: body
       label: Body
       display_summary: false
+      allowed_formats: {  }
   ids:
     entity_type:
       type: string
diff --git a/core/modules/book/config/optional/field.field.node.book.body.yml b/core/modules/book/config/optional/field.field.node.book.body.yml
index b97b9fa8b9..3fdd7c2d27 100644
--- a/core/modules/book/config/optional/field.field.node.book.body.yml
+++ b/core/modules/book/config/optional/field.field.node.book.body.yml
@@ -18,4 +18,5 @@ default_value: {  }
 default_value_callback: ''
 settings:
   display_summary: true
+  allowed_formats: {  }
 field_type: text_with_summary
diff --git a/core/modules/ckeditor/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php b/core/modules/ckeditor/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php
index a9ee69719b..a76a0386c2 100644
--- a/core/modules/ckeditor/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php
+++ b/core/modules/ckeditor/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php
@@ -58,7 +58,10 @@ protected function setUp() {
       'field_storage' => $field_storage,
       'bundle' => 'page',
       'label' => 'Body',
-      'settings' => ['display_summary' => TRUE],
+      'settings' => [
+        'display_summary' => TRUE,
+        'allowed_formats' => [],
+      ],
       'required' => TRUE,
     ])->save();
 
diff --git a/core/modules/config_translation/tests/src/Functional/ConfigTranslationListUiTest.php b/core/modules/config_translation/tests/src/Functional/ConfigTranslationListUiTest.php
index 1d0116dc99..2b5c77a904 100644
--- a/core/modules/config_translation/tests/src/Functional/ConfigTranslationListUiTest.php
+++ b/core/modules/config_translation/tests/src/Functional/ConfigTranslationListUiTest.php
@@ -404,7 +404,10 @@ public function doFieldListTest() {
       'field_storage' => FieldStorageConfig::loadByName('block_content', 'body'),
       'bundle' => $block_content_type->id(),
       'label' => 'Body',
-      'settings' => ['display_summary' => FALSE],
+      'settings' => [
+        'display_summary' => FALSE,
+        'allowed_formats' => [],
+      ],
     ]);
     $field->save();
 
diff --git a/core/modules/field/tests/src/Functional/Rest/FieldConfigResourceTestBase.php b/core/modules/field/tests/src/Functional/Rest/FieldConfigResourceTestBase.php
index 40ce43f578..3abca643f3 100644
--- a/core/modules/field/tests/src/Functional/Rest/FieldConfigResourceTestBase.php
+++ b/core/modules/field/tests/src/Functional/Rest/FieldConfigResourceTestBase.php
@@ -82,7 +82,9 @@ protected function getExpectedNormalizedEntity() {
       'label' => 'field_llama',
       'langcode' => 'en',
       'required' => FALSE,
-      'settings' => [],
+      'settings' => [
+        'allowed_formats' => [],
+      ],
       'status' => TRUE,
       'translatable' => TRUE,
       'uuid' => $this->entity->uuid(),
diff --git a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php
index 6c4e29c4be..ff55ce7479 100644
--- a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php
+++ b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldInstanceTest.php
@@ -31,7 +31,7 @@ public function testFieldInstanceMigration() {
     $field = FieldConfig::load('node.story.field_test');
     $this->assertIdentical('Text Field', $field->label());
     // field_test is a text_long field, which have no settings.
-    $this->assertIdentical([], $field->getSettings());
+    $this->assertIdentical(['allowed_formats' => []], $field->getSettings());
     $this->assertIdentical('text for default value', $entity->field_test->value);
 
     // Test a number field.
diff --git a/core/modules/forum/config/optional/field.field.comment.comment_forum.comment_body.yml b/core/modules/forum/config/optional/field.field.comment.comment_forum.comment_body.yml
index 215199cc22..8c6fa4c571 100644
--- a/core/modules/forum/config/optional/field.field.comment.comment_forum.comment_body.yml
+++ b/core/modules/forum/config/optional/field.field.comment.comment_forum.comment_body.yml
@@ -16,5 +16,6 @@ required: true
 translatable: true
 default_value: {  }
 default_value_callback: ''
-settings: {  }
+settings:
+  allowed_formats: {  }
 field_type: text_long
diff --git a/core/modules/forum/config/optional/field.field.node.forum.body.yml b/core/modules/forum/config/optional/field.field.node.forum.body.yml
index af6f7ad123..57fa67e72a 100644
--- a/core/modules/forum/config/optional/field.field.node.forum.body.yml
+++ b/core/modules/forum/config/optional/field.field.node.forum.body.yml
@@ -18,4 +18,5 @@ default_value: {  }
 default_value_callback: ''
 settings:
   display_summary: true
+  allowed_formats: {  }
 field_type: text_with_summary
diff --git a/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php b/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php
index 7c9a74ab50..4a2ec33688 100644
--- a/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php
+++ b/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php
@@ -51,7 +51,10 @@ protected function setUp() {
       'field_storage' => $field_storage,
       'bundle' => 'page',
       'label' => 'Body',
-      'settings' => ['display_summary' => TRUE],
+      'settings' => [
+        'display_summary' => TRUE,
+        'allowed_formats' => [],
+      ],
       'required' => TRUE,
     ])->save();
 
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 818fc899ac..451996634e 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -358,7 +358,10 @@ function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
       'field_storage' => $field_storage,
       'bundle' => $type->id(),
       'label' => $label,
-      'settings' => ['display_summary' => TRUE],
+      'settings' => [
+        'display_summary' => TRUE,
+        'allowed_formats' => [],
+      ],
     ]);
     $field->save();
 
diff --git a/core/modules/options/tests/options_config_install_test/config/install/field.field.node.options_install_test.body.yml b/core/modules/options/tests/options_config_install_test/config/install/field.field.node.options_install_test.body.yml
index 2078a84485..ac288b88f3 100644
--- a/core/modules/options/tests/options_config_install_test/config/install/field.field.node.options_install_test.body.yml
+++ b/core/modules/options/tests/options_config_install_test/config/install/field.field.node.options_install_test.body.yml
@@ -16,5 +16,6 @@ default_value: {  }
 default_value_callback: ''
 settings:
   display_summary: true
+  allowed_formats: {  }
 third_party_settings: {  }
 field_type: text_with_summary
diff --git a/core/modules/text/config/schema/text.schema.yml b/core/modules/text/config/schema/text.schema.yml
index dfc92cd2ba..6bc711a695 100644
--- a/core/modules/text/config/schema/text.schema.yml
+++ b/core/modules/text/config/schema/text.schema.yml
@@ -19,6 +19,12 @@ field.storage_settings.text:
 field.field_settings.text:
   type: mapping
   label: 'Text (formatted) settings'
+  mapping:
+    allowed_formats:
+      type: sequence
+      label: 'Allowed text formats'
+      sequence:
+        type: string
 
 field.value.text:
   type: mapping
@@ -38,6 +44,12 @@ field.storage_settings.text_long:
 field.field_settings.text_long:
   label: 'Text (formatted, long) settings'
   type: mapping
+  mapping:
+    allowed_formats:
+      type: sequence
+      label: 'Allowed text formats'
+      sequence:
+        type: string
 
 field.value.text_long:
   type: mapping
@@ -61,6 +73,11 @@ field.field_settings.text_with_summary:
     display_summary:
       type: boolean
       label: 'Summary input'
+    allowed_formats:
+      type: sequence
+      label: 'Allowed text formats'
+      sequence:
+        type: string
 
 field.value.text_with_summary:
   type: mapping
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php b/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php
index e70fadacb1..6d8850edfb 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php
@@ -7,12 +7,38 @@
 use Drupal\Core\Field\FieldItemBase;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Base class for 'text' configurable field types.
  */
 abstract class TextItemBase extends FieldItemBase {
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultFieldSettings() {
+    return ['allowed_formats' => []] + parent::defaultFieldSettings();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
+    $element = parent::fieldSettingsForm($form, $form_state);
+    $settings = $this->getSettings();
+
+    $element['allowed_formats'] = [
+      '#type' => 'checkboxes',
+      '#title' => t('Allowed text formats'),
+      '#options' => $this->getProperties()['format']->getPossibleOptions(),
+      '#default_value' => $settings['allowed_formats'],
+      '#description' => t('Select the allowed text formats. If no formats are selected, all available text formats will be displayed to the user.'),
+    ];
+
+    return $element;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
index 6af6d0431f..6d08bf2cf7 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
@@ -85,7 +85,7 @@ public function isEmpty() {
    * {@inheritdoc}
    */
   public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
-    $element = [];
+    $element = parent::fieldSettingsForm($form, $form_state);
     $settings = $this->getSettings();
 
     $element['display_summary'] = [
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
index 69a660e4db..fc15a2bbe3 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
@@ -34,11 +34,20 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    */
   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $main_widget = parent::formElement($items, $delta, $element, $form, $form_state);
+    $allowed_formats_setting = $this->getFieldSetting('allowed_formats');
 
     $element = $main_widget['value'];
     $element['#type'] = 'text_format';
     $element['#format'] = $items[$delta]->format;
     $element['#base_type'] = $main_widget['value']['#type'];
+
+    if (is_array($allowed_formats_setting)) {
+      $allowed_formats = array_filter($allowed_formats_setting);
+      if (!empty($allowed_formats) && !$this->isDefaultValueWidget($form_state)) {
+        $element['#allowed_formats'] = $allowed_formats;
+      }
+    }
+
     return $element;
   }
 
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
index af8493de08..14188e1113 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
@@ -25,11 +25,17 @@ class TextfieldWidget extends StringTextfieldWidget {
    */
   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $main_widget = parent::formElement($items, $delta, $element, $form, $form_state);
+    $allowed_formats = $this->getFieldSetting('allowed_formats');
 
     $element = $main_widget['value'];
     $element['#type'] = 'text_format';
     $element['#format'] = isset($items[$delta]->format) ? $items[$delta]->format : NULL;
     $element['#base_type'] = $main_widget['value']['#type'];
+
+    if (!empty($allowed_formats) && !$this->isDefaultValueWidget($form_state)) {
+      $element['#allowed_formats'] = $allowed_formats;
+    }
+
     return $element;
   }
 
diff --git a/core/modules/text/src/Tests/TextFieldTest.php b/core/modules/text/src/Tests/TextFieldTest.php
index ecdb0af06d..6b1576df24 100644
--- a/core/modules/text/src/Tests/TextFieldTest.php
+++ b/core/modules/text/src/Tests/TextFieldTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\text\Tests;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\entity_test\Entity\EntityTest;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Tests\String\StringFieldTest;
@@ -140,6 +141,79 @@ public function testTextfieldWidgetsFormatted() {
     $this->_testTextfieldWidgetsFormatted('text_long', 'text_textarea');
   }
 
+  /**
+   * Test widgets for fields with selected allowed formats.
+   */
+  public function testTextfieldWidgetsAllowedFormats() {
+    // Create one text format.
+    $this->drupalLogin($this->adminUser);
+    $edit = [
+      'format' => Unicode::strtolower($this->randomMachineName()),
+      'name' => $this->randomMachineName(),
+    ];
+    $this->drupalPostForm('admin/config/content/formats/add', $edit, t('Save configuration'));
+    filter_formats_reset();
+    $filter_format_storage = \Drupal::entityTypeManager()->getStorage('filter_format');
+    /** @var \Drupal\filter\Entity\FilterFormat $format1 */
+    $format1 = $filter_format_storage->load($edit['format']);
+
+    // Create a second text format.
+    $edit = [
+      'format' => Unicode::strtolower($this->randomMachineName()),
+      'name' => $this->randomMachineName(),
+    ];
+    $this->drupalPostForm('admin/config/content/formats/add', $edit, t('Save configuration'));
+    filter_formats_reset();
+    /** @var \Drupal\filter\Entity\FilterFormat $format2 */
+    $format2 = $filter_format_storage->load($edit['format']);
+
+    // Grant access to both formats to the user.
+    $roles = $this->webUser->getRoles();
+    $rid = $roles[0];
+    user_role_grant_permissions($rid, [
+      $format1->getPermissionName(),
+      $format2->getPermissionName(),
+    ]);
+
+    // Create a field with multiple formats allowed.
+    $field_name = Unicode::strtolower($this->randomMachineName());
+    $field_storage = entity_create('field_storage_config', [
+      'field_name' => $field_name,
+      'entity_type' => 'entity_test',
+      'type' => 'text',
+    ]);
+    $field_storage->save();
+    $field = entity_create('field_config', [
+      'field_storage' => $field_storage,
+      'bundle' => 'entity_test',
+      'label' => $this->randomMachineName() . '_label',
+      'settings' => ['allowed_formats' => [$format1->id(), $format2->id()]],
+    ]);
+    $field->save();
+    entity_get_form_display('entity_test', 'entity_test', 'default')
+      ->setComponent($field_name, [
+        'type' => 'text_textfield',
+      ])
+      ->save();
+    entity_get_display('entity_test', 'entity_test', 'full')
+      ->setComponent($field_name)
+      ->save();
+
+    // Display the creation form.
+    $this->drupalLogin($this->webUser);
+    $this->drupalGet('entity_test/add');
+    $this->assertFieldByName("{$field_name}[0][value]", NULL, 'Widget is displayed');
+    $this->assertFieldByName("{$field_name}[0][format]", NULL, 'Format selector is displayed');
+
+    // Change field to allow only one format.
+    $field->setSetting('allowed_formats', [$format1->id()]);
+    $field->save();
+    // We shouldn't have the 'format' selector since only one format is allowed.
+    $this->drupalGet('entity_test/add');
+    $this->assertFieldByName("{$field_name}[0][value]", NULL, 'Widget is displayed');
+    $this->assertNoFieldByName("{$field_name}[0][format]", NULL, 'Format selector is not displayed');
+  }
+
   /**
    * Helper function for testTextfieldWidgetsFormatted().
    */
@@ -181,8 +255,8 @@ public function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
     // Display the creation form. Since the user only has access to one format,
     // no format selector will be displayed.
     $this->drupalGet('entity_test/add');
-    $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
-    $this->assertNoFieldByName("{$field_name}[0][format]", '', 'Format selector is not displayed');
+    $this->assertFieldByName("{$field_name}[0][value]", NULL, 'Widget is displayed');
+    $this->assertNoFieldByName("{$field_name}[0][format]", NULL, 'Format selector is not displayed');
 
     // Submit with data that should be filtered.
     $value = '<em>' . $this->randomMachineName() . '</em>';
diff --git a/core/modules/views/tests/src/Kernel/Entity/ViewEntityDependenciesTest.php b/core/modules/views/tests/src/Kernel/Entity/ViewEntityDependenciesTest.php
index 34f58122ca..3ce6488978 100644
--- a/core/modules/views/tests/src/Kernel/Entity/ViewEntityDependenciesTest.php
+++ b/core/modules/views/tests/src/Kernel/Entity/ViewEntityDependenciesTest.php
@@ -73,7 +73,10 @@ protected function setUp($import_test_views = TRUE) {
       'field_storage' => FieldStorageConfig::loadByName('node', 'body'),
       'bundle' => $content_type->id(),
       'label' => $this->randomMachineName() . '_body',
-      'settings' => ['display_summary' => TRUE],
+      'settings' => [
+        'display_summary' => TRUE,
+        'allowed_formats' => [],
+      ],
     ])->save();
 
     ViewTestData::createTestViews(get_class($this), ['views_test_config']);
diff --git a/core/profiles/demo_umami/config/install/field.field.block_content.basic.body.yml b/core/profiles/demo_umami/config/install/field.field.block_content.basic.body.yml
index 89118eff08..8f00859c1c 100644
--- a/core/profiles/demo_umami/config/install/field.field.block_content.basic.body.yml
+++ b/core/profiles/demo_umami/config/install/field.field.block_content.basic.body.yml
@@ -18,4 +18,5 @@ default_value: {  }
 default_value_callback: ''
 settings:
   display_summary: false
+  allowed_formats: {  }
 field_type: text_with_summary
diff --git a/core/profiles/demo_umami/config/install/field.field.block_content.disclaimer_block.field_copyright.yml b/core/profiles/demo_umami/config/install/field.field.block_content.disclaimer_block.field_copyright.yml
index 964a88887c..30cbbdbb05 100644
--- a/core/profiles/demo_umami/config/install/field.field.block_content.disclaimer_block.field_copyright.yml
+++ b/core/profiles/demo_umami/config/install/field.field.block_content.disclaimer_block.field_copyright.yml
@@ -16,5 +16,6 @@ required: false
 translatable: true
 default_value: {  }
 default_value_callback: ''
-settings: {  }
+settings:
+  allowed_formats: {  }
 field_type: text_long
diff --git a/core/profiles/standard/config/install/field.field.block_content.basic.body.yml b/core/profiles/standard/config/install/field.field.block_content.basic.body.yml
index 89118eff08..8f00859c1c 100644
--- a/core/profiles/standard/config/install/field.field.block_content.basic.body.yml
+++ b/core/profiles/standard/config/install/field.field.block_content.basic.body.yml
@@ -18,4 +18,5 @@ default_value: {  }
 default_value_callback: ''
 settings:
   display_summary: false
+  allowed_formats: {  }
 field_type: text_with_summary
diff --git a/core/profiles/standard/config/install/field.field.comment.comment.comment_body.yml b/core/profiles/standard/config/install/field.field.comment.comment.comment_body.yml
index 1337070d16..8d97e03507 100644
--- a/core/profiles/standard/config/install/field.field.comment.comment.comment_body.yml
+++ b/core/profiles/standard/config/install/field.field.comment.comment.comment_body.yml
@@ -16,5 +16,6 @@ required: true
 translatable: true
 default_value: {  }
 default_value_callback: ''
-settings: {  }
+settings:
+  allowed_formats: {  }
 field_type: text_long
diff --git a/core/profiles/standard/config/install/field.field.node.article.body.yml b/core/profiles/standard/config/install/field.field.node.article.body.yml
index 8f3681d962..9ac4f523a2 100644
--- a/core/profiles/standard/config/install/field.field.node.article.body.yml
+++ b/core/profiles/standard/config/install/field.field.node.article.body.yml
@@ -18,4 +18,5 @@ default_value: {  }
 default_value_callback: ''
 settings:
   display_summary: true
+  allowed_formats: {  }
 field_type: text_with_summary
diff --git a/core/profiles/standard/config/install/field.field.node.page.body.yml b/core/profiles/standard/config/install/field.field.node.page.body.yml
index 6c09432b41..8ecd10344e 100644
--- a/core/profiles/standard/config/install/field.field.node.page.body.yml
+++ b/core/profiles/standard/config/install/field.field.node.page.body.yml
@@ -18,4 +18,5 @@ default_value: {  }
 default_value_callback: ''
 settings:
   display_summary: true
+  allowed_formats: {  }
 field_type: text_with_summary
