Edit: Little More Description: For adding entity type (content type, block type, product type, variation type ... ) field programmatically you need
- Create Field Storage Configuration: only then
- Create Field Configuration
You can use Drupal 8 configuration Single export which can be found here -> /admin/config/development/configuration/single/export
Selecting needed Field Storage or Field config will give you desired fields and their values.

Next All Described Very Well
I like to add, that the node modules code uses some deprecated functions. (We are now 8.5.6).
Here's my part of the code which handles "create a field storage programmatically:
if (empty($fieldStorageMicrositesfield = \Drupal\field\Entity\FieldStorageConfig::loadByName('node', $fieldName))) {
$fieldStorage = \Drupal\field\Entity\FieldStorageConfig::create(
[
'field_name' => $fieldName,
'langcode' => 'en',
'entity_type' => 'node',
'type' => 'list_string',
'settings' => [
'allowed_values' => [],
'allowed_values_function' => 'I_used_a_custum_function_here_which_you_not_need_I_guess',
],
'module' => 'options',
'locked' => FALSE,
'cardinality' => -1,
'translatable' => TRUE,
'persist_with_no_fields' => FALSE,
'custom_storage' => FALSE,
]
);
$fieldStorageSaved = $fieldStorage->save();
if ($fieldStorageSaved) {
$message = t(
"Field @a storage created.",
['@a' => $fieldName,]
);
}
else {
$message = t(
"Field @a storage could not be created.",
['@a' => $fieldName,]
);
}
}
else {
$message = t(
"Field @a storage could not be created because the field already exists",
['@a' => $fieldName,]
);
}
Here's my part of the code which handles the adding of a field to several content types after I created the storage ($bundles
holds the array of my content types):
$entityTypemanager = \Drupal::entityTypeManager();
foreach ($bundles as $bundle) {
$field = FieldConfig::loadByName('node', $bundle, $fieldName);
if (empty($field)) {
FieldConfig::create(
[
'field_name' => $fieldName,
'entity_type' => 'node',
'bundle' => $bundle,
'label' => $label,
'required' => TRUE,
'translatable' => TRUE,
'description' => t(
$description
),
]
)->save();
$message .= "\n" . t(
"Field @a created in bundle @b.",
['@a' => $fieldName, '@b' => $bundle]
);
// Assign widget settings for the 'default' form mode.
$displayForm = $entityTypemanager
->getStorage('entity_form_display')
->load('node.' . $bundle . '.default')
->setComponent($fieldName, [
'type' => 'options_buttons',
'weight' => 100,
]);
$messagePart = '';
if ($displayForm->save()) {
$messagePart .= ' form-';
}
else {
$message .= "\n" . t(
"The form display of @a in bundle @b could not be set",
['@a' => $fieldName, '@b' => $bundle]
);
}
unset($displayForm);
// Assign display settings for the 'default' and 'teaser' view modes.
$displayDefault = $entityTypemanager
->getStorage('entity_view_display')
->load('node.' . $bundle . '.default')
->removeComponent($fieldName);
if ($displayDefault->save()) {
$messagePart .= ' default-';
}
else {
$message .= "\n" . t(
"The default display of @a in bundle @b could not be set",
['@a' => $fieldName, '@b' => $bundle]
);
}
unset($displayDefault);
// The teaser view mode is created by the Standard profile and therefore
// might not exist.
$viewModes = \Drupal::service('entity_display.repository')
->getViewModes('node');
if (isset($viewModes['teaser'])) {
$displayTeaser = $entityTypemanager
->getStorage('entity_view_display')
->load('node.' . $bundle . '.teaser')
->removeComponent($fieldName);
if ($displayTeaser->save()) {
$messagePart .= ' teaser-';
}
else {
$message .= "\n" . t(
"The teaser display of @a in bundle @b could not be set",
['@a' => $fieldName, '@b' => $bundle]
);
}
unset($displayTeaser);
}
$message .= "\n" . t(
$messagePart . "Display(s) of @a in bundle @b are set.",
['@a' => $fieldName, '@b' => $bundle]
);
}
else {
$message .= "\n" . t(
"Field @a already exists in bundle @b.",
['@a' => $fieldName, '@b' => $bundle]
);
}
}