Constraint doesn't attach from BundleFieldDefinition, but does from entity_bundle_field_info_alter() I'm adding a trait to Commerce Product Variations, which applies the following

  public function buildFieldDefinitions() {
    // Builds the field definitions.
    $fields = [];
    $fields['plan_code'] = BundleFieldDefinition::create('string')
      -&gt;setLabel(t('Recurly Plan Code'))
      -&gt;setDescription(t('The Plan Code of the related Recurly plan.'))
      -&gt;setCardinality(1)
      -&gt;setRequired(TRUE)
      -&gt;setDisplayConfigurable('form', FALSE)
      -&gt;setDisplayConfigurable('view', FALSE)
      -&gt;addConstraint('RecurlyPlanCodeExists', []);
    return $fields;
  }


The plan_code field appears on product variations as expected when the trait is enabled, but the field is not validated against RecurlyPlanCodeExists when the entity is saved. However, if I add the constraint via hook, as in the following, the constraint is attached and validation runs as expected.

/**
 * Implements hook_entity_bundle_field_info_alter().
 */
function commerce_recurly_entity_bundle_field_info_alter(&amp;$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
    if ($bundle === 'recurly_plan_variation') {
      if (isset($fields['plan_code'])) {
        $fields['plan_code']-&gt;addConstraint('RecurlyPlanCodeExists', []);
      }
    }
}


Inspecting $fields['plan_code'] in the above hook confirms no constraints exist on the field prior to adding $fields['plan_code']-&gt;addConstraint('RecurlyPlanCodeExists', []);. Interestingly, $fields['plan_code']['description'] is also an empty string despite being defined in the BundleFieldDefinition. I'd assume that these are related. Any idea what the cause might be?

I've already tried deleting all existing variations and disabling/re-enabling the trait and it's had no effect.

EDIT: I just realized that the docs refer to adding constraints to BaseFieldDefinition, while I'm using BundleFieldDefinition. Maybe this is the reason?
Yes, both are different. In core the system to define bundle fields in code is broken from the beginning. Commerce did implement their own system (entity traits), but although it looks like the fields are defined in code, in reality they are not. Commerce adds them to config and doesn't transfer constraints in this process.