Parameter upcasting in Forms: buildForm works, submitForm doesn't Route:

mymodule.applications.payment_form:
  path: '/payment/{submission}'
  defaults:
    _form: '\Drupal\mymodule\Form\PaymentForm'
    _title: 'Pay Fee'
  requirements:
    _role: 'applicant'
  options:
    parameters:
      submission:
        type: entity:webform_submission


This works:

public function buildForm( array $form, FormStateInterface $form_state, WebformSubmission $submission = NULL) {
    $submission_data = $submission-&gt;getData();


This doesn't (null):

public function submitForm(array &amp;$form, FormStateInterface $form_state, WebformSubmission $submission = NULL) {
    $submission_data = $submission-&gt;getData();


Is it intentional that upcasting is only available to buildForm?
Is there a workaround?

(My logic being: the form, when submitted, still POSTs to /payment/123, so it's still convenient to load the object.)
Yes, this is intentational. submit and validate callbacks aren't tied to the request, they only receive exactly those two arguments.

As mentioned in the comments, you can store the information either on the object, with $form_state->get()/set() or a form elemnt of #type value, doesn't make a big difference which you chose.

You could also store only the ID instead of the whole object but actually, I believe it is stored anyway in form_state somewhere when you pass it as an argument to the form (pretty well hidden though, so better to store &amp; access it in a more explicit place)