How to avoid calling performRequiredValidation() for custom element
That error is caused from the following code.

  if (isset($elements['#options']) &amp;&amp; isset($elements['#value'])) {
    if ($elements['#type'] == 'select') {
      $options = OptGroup::flattenOptions($elements['#options']);
    }
    else {
      $options = $elements['#options'];
    }
    if (is_array($elements['#value'])) {
      $value = in_array($elements['#type'], array('checkboxes', 'tableselect')) ? array_keys($elements['#value']) : $elements['#value'];
      foreach ($value as $v) {
        if (!isset($options[$v])) {
          $form_state-&gt;setError($elements, $this-&gt;t('An illegal choice has been detected. Please contact the site administrator.'));
          $this-&gt;logger-&gt;error('Illegal choice %choice in %name element.', array('%choice' =&gt; $v, '%name' =&gt; empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title']));
        }
      }
    }
    // Non-multiple select fields always have a value in HTML. If the user
    // does not change the form, it will be the value of the first option.
    // Because of this, form validation for the field will almost always
    // pass, even if the user did not select anything. To work around this
    // browser behavior, required select fields without a #default_value
    // get an additional, first empty option. In case the submitted value
    // is identical to the empty option's value, we reset the element's
    // value to NULL to trigger the regular #required handling below.
    // @see \Drupal\Core\Render\Element\Select::processSelect()
    elseif ($elements['#type'] == 'select' &amp;&amp; !$elements['#multiple'] &amp;&amp; $elements['#required'] &amp;&amp; !isset($elements['#default_value']) &amp;&amp; $elements['#value'] === $elements['#empty_value']) {
      $elements['#value'] = NULL;
      $form_state-&gt;setValueForElement($elements, NULL);
    }
    elseif (!isset($options[$elements['#value']])) {
      $form_state-&gt;setError($elements, $this-&gt;t('An illegal choice has been detected. Please contact the site administrator.'));
      $this-&gt;logger-&gt;error('Illegal choice %choice in %name element.', array('%choice' =&gt; $elements['#value'], '%name' =&gt; empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title']));
    }
  }


It means that the value set for $elements['#value'] (which could also be a value submitted from the users) is not contained in $elements['#options']. In fact, your code contains the following code.

$grouped_types = _getTypesGrouped();

// Override select form element.
$element['#settings'] = [
  'plugins' =&gt; ['optgroup_columns'],
];
$element['#type'] = 'selectize';
$element['#options'] = $grouped_types;


Since there isn't a _getTypesGrouped() function, you are essentially setting $element['#options'] to NULL, which means you are removing all the possible values the form field for that widget can have.
The correct code you want to use is the following one.

$grouped_types = $this-&gt;_getTypesGrouped();

// Override select form element.
$element['#settings'] = [
  'plugins' =&gt; ['optgroup_columns'],
];
$element['#type'] = 'selectize';
$element['#options'] = $grouped_types;


As for avoiding Drupal runs FormValidator::performRequiredValidation(), that is a bad idea. The purpose of that method is avoiding users submit a forget form; removing it means to mine the site security.

As side note, protected method don't need an underscore at the beginning of their name, as per Drupal coding standards.