save_post_{$post->post_type} action firing on second save

I think you’d have to move the check for whether or not the $location === header into the metabox then use the following to save the meta data.

Like this:

//In your metabox before the fields
$location       = get_post_meta( $post->ID, '_est_template_location', true );
if( empty( $location ) || $location != 'header' ) :
    $location = 'other';
endif;

Then, when saving, you’ve already addressed everything else and it’s a straightforward saving process.

add_action( 'save_post', 'clean_deactivated_theme_templates_post_meta', 1, 2 );
function clean_deactivated_theme_templates_post_meta( $post_id, $post ) {
    if( !current_user_can( 'edit_post', $post_id ) ) {
        return $post_id;
    }
    if( !isset( $_POST['theme_template_fields'] ) || !wp_verify_nonce( $_POST['theme_template_fields'], basename( __FILE__ ) ) ) {
        return $post_id;
    }
    $theme_template_meta['_est_template_location']      = esc_textarea( $_POST['_est_template_location'] );
    foreach( $theme_template_meta as $key => $value ) :
        if( 'revision' === $post->post_type ) {
            return;
        }
        if( get_post_meta( $post_id, $key, false ) ) {
            update_post_meta( $post_id, $key, $value );
        } else {
            add_post_meta( $post_id, $key, $value);
        }
        if( !$value ) {
            delete_post_meta( $post_id, $key );
        }
    endforeach;
}