While working on a timekeeping module I encountered an issue that couldn't be resolved with the config/install & config/optional combinations. This module requires other modules to be installed first, but then some field group manipulation was needed to add the timekeeping tab into the tabs on the main page, luckily, there are tests on the field group module, so with a bit of looking through tests and experimenting, it ends up like this:

hook_install() code

function se_timekeeping_install() {

  // Create a definition for the new field group.
  $field_group = (object) [
    'group_name' => 'group_cu_tab_timekeeping',
    'entity_type' => 'node',
    'bundle' => 'se_customer',
    'mode' => 'default',
    'context' => 'view',
    'children' => [
      0 => 'se_timekeeping_eva_entity_view_1',
    'parent_name' => 'group_cu_tabs',
    'weight' => 10,
    'label' => 'Timekeeping',
    'format_type' => 'tab',
    'format_settings' => [
      'id' => '',
      'classes' => '',
      'description' => '',
      'formatter' => 'closed',
    'region' => 'content',

  // Add the new group to the existing tabs on the customer node view.
  $group = field_group_load_field_group('group_cu_tabs', 'node', 'se_customer', 'view', 'default'); 
  $group->children[] = 'group_cu_tab_timekeeping';


hook_uninstall() code

function se_timekeeping_uninstall() {

  // Remove the timekeeping list tab from the customer display.
  if ($group = field_group_load_field_group('group_cu_tabs', 'node', 'se_customer', 'view', 'default')) {
    $group->children = array_diff($group->children, ['group_cu_tab_timekeeping']);

  // Now remove the timekeeping tab group.
  if ($group = field_group_load_field_group('group_cu_tab_timekeeping', 'node', 'se_customer', 'view', 'default')) {


group_cu_tabs is the existing tab group on the customer view display, se_customer is the node type and group_cu_tab_timekeeping is the tab element that is created with an eva entity view.

Module reference list