Unexpected script loading order

Simple Fix

The reason why your code does not work is because the third parameter of the wp_enqueue_script() function is expecting an array, not a string.

Just replace 'footer-js' with array('footer-js') and it will work:

function tallulah_scripts() {
  wp_enqueue_script( 'header-js', get_template_directory_uri() . '/js/header.min.js', null, '1.0', false );
  wp_deregister_script('jquery');
  wp_enqueue_script( 'footer-js', get_template_directory_uri() . '/js/footer.min.js', null, '1.0', true );
  wp_enqueue_script( 'jquery', get_template_directory_uri() . '/js/jquery.min.js', array('footer-js'), '2.1.0', true ); // Note the footer-js dependency
}
add_action( 'wp_enqueue_scripts', 'tallulah_scripts');

Alternative Solution

The less common (and not so recommended) way to deal with this is to output your own tag to include jQuery anywhere you wish, literally.

The first step is to remove jQuery from the global scripts array just before WordPress is about to process it, we do so using the print_scripts_array filter hook and deleting the jQuery entry from the array.

The second step is to just echo a custom <script> tag pointing to the jQuery script, it could be echoed using any action hook, or even put in any template file manually (not recommended), in this example I’m using the wp_footer hook with a low priority so the script is inserted after any other elements associated with wp_footer (basically at the very end of the page).

// Force remove default jQuery
add_filter('print_scripts_array', 'remove_jquery');
function remove_jquery($scripts) {
    $key = array_search('jquery', $scripts);
    if ($key !== false) {
        unset($scripts[$key]);
    }
    return $scripts; 
}

// Print custom jQuery wherever you want
add_action('wp_footer', 'print_custom_jquery', 200);
function print_custom_jquery() {
    echo '<script src="'.get_template_directory_uri().'/js/jquery.min.js"></script>';
}