diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php
index 71aea12b80..4fd8d0290e 100644
--- a/core/lib/Drupal/Core/Entity/EntityType.php
+++ b/core/lib/Drupal/Core/Entity/EntityType.php
@@ -7,6 +7,7 @@
 use Drupal\Core\Entity\Exception\EntityTypeIdLengthException;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\TypedData\InternalizeViaSettingsTrait;
 
 /**
  * Provides an implementation of an entity type and its metadata.
@@ -17,6 +18,7 @@ class EntityType extends PluginDefinition implements EntityTypeInterface {
 
   use DependencySerializationTrait;
   use StringTranslationTrait;
+  use InternalizeViaSettingsTrait;
 
   /**
    * Indicates whether entities should be statically cached.
@@ -370,6 +372,11 @@ public function set($property, $value) {
    * {@inheritdoc}
    */
   public function isInternal() {
+    // Allow settings.php to force this to be internal, regardless of anything
+    // else.
+    if ($this->internalizeViaSettings($this->getClass())) {
+      return TRUE;
+    }
     return $this->internal;
   }
 
diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
index cc41f2eca5..c7394b5071 100644
--- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\Entity\BaseFieldOverride;
 use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
+use Drupal\Core\TypedData\InternalizeViaSettingsTrait;
 use Drupal\Core\TypedData\ListDataDefinition;
 use Drupal\Core\TypedData\OptionsProviderInterface;
 
@@ -16,6 +17,7 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI
 
   use UnchangingCacheableDependencyTrait;
   use FieldInputValueNormalizerTrait;
+  use InternalizeViaSettingsTrait;
 
   /**
    * The field type.
@@ -876,6 +878,11 @@ public function __clone() {
    * {@inheritdoc}
    */
   public function isInternal() {
+    // Allow settings.php to force this to be internal, regardless of anything
+    // else.
+    if ($this->internalizeViaSettings($this->getItemDefinition()->getClass())) {
+      return TRUE;
+    }
     // All fields are not internal unless explicitly set.
     return !empty($this->definition['internal']);
   }
diff --git a/core/lib/Drupal/Core/Field/FieldConfigBase.php b/core/lib/Drupal/Core/Field/FieldConfigBase.php
index ac6596f82a..b0f736aa01 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigBase.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
+use Drupal\Core\TypedData\InternalizeViaSettingsTrait;
 
 /**
  * Base class for configurable field definitions.
@@ -13,6 +14,7 @@
 abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigInterface {
 
   use FieldInputValueNormalizerTrait;
+  use InternalizeViaSettingsTrait;
 
   /**
    * The field ID.
@@ -586,6 +588,11 @@ public function addPropertyConstraints($name, array $constraints) {
    * {@inheritdoc}
    */
   public function isInternal() {
+    // Allow settings.php to force this to be internal, regardless of anything
+    // else.
+    if ($this->internalizeViaSettings($this->getItemDefinition()->getClass())) {
+      return TRUE;
+    }
     // Respect the definition, otherwise default to TRUE for computed fields.
     if (isset($this->definition['internal'])) {
       return $this->definition['internal'];
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinition.php b/core/lib/Drupal/Core/TypedData/DataDefinition.php
index 23b2f09878..44e6370ba4 100644
--- a/core/lib/Drupal/Core/TypedData/DataDefinition.php
+++ b/core/lib/Drupal/Core/TypedData/DataDefinition.php
@@ -8,6 +8,7 @@
 class DataDefinition implements DataDefinitionInterface, \ArrayAccess {
 
   use TypedDataTrait;
+  use InternalizeViaSettingsTrait;
 
   /**
    * The array holding values for all definition keys.
@@ -363,6 +364,11 @@ public function __sleep() {
    * {@inheritdoc}
    */
   public function isInternal() {
+    // Allow settings.php to force this to be internal, regardless of anything
+    // else.
+    if ($this->internalizeViaSettings($this->getClass())) {
+      return TRUE;
+    }
     // Respect the definition, otherwise default to TRUE for computed fields.
     if (isset($this->definition['internal'])) {
       return $this->definition['internal'];
diff --git a/core/lib/Drupal/Core/TypedData/InternalizeViaSettingsTrait.php b/core/lib/Drupal/Core/TypedData/InternalizeViaSettingsTrait.php
new file mode 100644
index 0000000000..31b0240de0
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/InternalizeViaSettingsTrait.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\Core\TypedData;
+
+use Drupal\Core\Site\Settings;
+
+/**
+ *
+ */
+trait InternalizeViaSettingsTrait {
+
+  private function internalizeViaSettings($class) {
+    $setting = Settings::get('typed_data_internalize');
+    $internalize = FALSE;
+    if (isset($setting['internalize'])) {
+      foreach ($setting['internalize'] as $test_class) {
+        if (is_a($class, $test_class, TRUE)) {
+          $internalize = TRUE;
+          break;
+        }
+      }
+    }
+    if ($internalize && isset($setting['except'])) {
+      foreach ($setting['except'] as $test_class) {
+        if (is_a($class, $test_class, TRUE)) {
+          $internalize = FALSE;
+          break;
+        }
+      }
+    }
+    return $internalize;
+  }
+}
