Create dynamic text fields on form based on other entities
Paragraphs is what you want. What you are describing is Paragraphs' exact use case. We use Paragraphs as a staple of our platform because of its re-usability.
Assigning an existing Paragraph to an Entity Reference Revisions field on a node is as simple as:
// Note that the value will be a nested array, even if cardinality is 1.
$node-&gt;get('field_food')&gt;setValue([
  [
    'target_id' =&gt; $paragraph-&gt;id(),
    'target_revision_id' =&gt; $paragraph-&gt;getRevisionId(),
  ],
]);
$node-&gt;save();

// Another example: assigning multiple references to a single field.
$node-&gt;get('field_myfield')&gt;setValue([
  [
    'target_id' =&gt; $paragraph1-&gt;id(),
    'target_revision_id' =&gt; $paragraph1-&gt;getRevisionId(),
  ],
  [
    'target_id' =&gt; $paragraph2-&gt;id(),
    'target_revision_id' =&gt; $paragraph2-&gt;getRevisionId(),
  ],
  [
    'target_id' =&gt; $paragraph3-&gt;id(),
    'target_revision_id' =&gt; $paragraph3-&gt;getRevisionId(),
  ],
]);
$node-&gt;save();

If you need to generate a paragraph programmatically, that is also easy:
// Note that I'm using the DIC for demonstration's sake.
// Be sure to use dependency injection and other best practices in your project.
$storage = \Drupal::entityTypeManager()-&gt;getStorage('paragraph');
$paragraph = $storage-&gt;create([
  'type' =&gt; 'food',
  'title' =&gt; 'A title',
  'field_a' =&gt; 'a value',
]);
$paragraph-&gt;save();

You can then assign this newly created paragraph to an Entity Reference Revisions field using the method I mentioned above.