Block cache not clearing on save?
The problem is, that the cache tag block_content:[id] does not bubble up and the tag is missing in the cache entry. Without this cache tag the cache entry can't be invalidated when saving a modified custom block.

Here are two workarounds:

Twig template (Workaround 1)

If you theme a block template and you render single fields

{{ content.field_field1 }}
{{ content.field_field2 }}


then you also need to render the rest of content:

{{ content|without('field_field1', 'field_field2') }}


That's because content contains the cache tag of the block content entity, which otherwise won't bubble up.

Preprocess (Workaround 2)

As an alternative option for rendering {{ content }} you can add the cache tag at the top of variables in preprocess.

mytheme.theme

function mytheme_preprocess_block(&amp;$variables) {
  if ($variables['base_plugin_id'] == 'block_content') {
    $renderer = \Drupal::service('renderer');
    $renderer-&gt;addCacheableDependency($variables, $variables['content']['#block_content']);
  }
}


Then you no longer depend on the twig template to render all of content. 

You'll find in Drupal\block\BlockViewBuilder::preRender() more workarounds for issues with bubbling up data from the content render array. You could use this code, which there is only applied in special circumstances, for all cache data from block content to bubble up to the top level:

use Drupal\Core\Cache\CacheableMetadata;

function mytheme_preprocess_block(&amp;$variables) {
  $content = $variables['content'];
  CacheableMetadata::createFromRenderArray($variables)
          -&gt;merge(CacheableMetadata::createFromRenderArray($content))
          -&gt;applyTo($variables);
}


But I don't know which side effects that would have in other places. If it would be that easy the block view builder would do this already. So it's better to tackle only that specific problem with the one missing tag and use the first version of the preprocess function.