Order item with persistent custom field value
I couldn't find a more elegant way but this works for me.
First I rebuild the purchased entity link in the commerce cart form view to include the custom text field value as a parameter in the link URL for when I navigate back from the cart to the product variation:
/**
 * Implements hook_preprocess_views_view_field().
 */
function MYMODULE_preprocess_views_view_field(&amp;$variables) {

  $view = $variables['view'];
  $field = $variables['field'];

  // Commerce cart form
  if (isset($view) &amp;&amp; ($view-&gt;id() === 'commerce_cart_form')) {

    switch($field-&gt;field) {
      case 'purchased_entity':

        // Get purchased entity
        $purchased_entity = $variables['row']-&gt;_relationship_entities['order_items']-&gt;purchased_entity-&gt;getValue();
        $purchased_entity_id = $purchased_entity[0]['target_id'];

        // Load product variation
        $product_variation = $variation = ProductVariation::load($purchased_entity_id);

        // Get product variation URL
        $url = Url::fromUserInput($product_variation-&gt;toLink()-&gt;getUrl()-&gt;toString());

        // Get custom field value
        $custom_field = $variables['row']-&gt;_relationship_entities['order_items']-&gt;field_custom-&gt;getValue();

        // Rebuild url with variation &amp; custom field value
        $url-&gt;setOption('query', [
          'v' =&gt; $purchased_entity_id,
          'custom' =&gt; $custom_field[0]['value'],
        ]);

        // Output
        $variables['output'] = Link::fromTextAndUrl(t($product_variation-&gt;label()), $url);

        break;
    }
  }
}

This will output a link like /product/1?v=2&amp;custom=MYVALUE
And then on the product add to cart form, if the param is in the URL, I set the default value of the custom field:
/**
 * Implements hook_form_alter().
 */
function MYMODULE_form_alter(&amp;$form, FormStateInterface $form_state, $form_id) {

  if (strpos($form_id, 'commerce_order_item_add_to_cart_form_commerce_product_') !== false) {

    // Set custom text form field value from URL
    $form['field_custom']['widget'][0]['value']['#default_value'] = \Drupal::request()-&gt;query-&gt;get('custom');
  }
}