the_title filter returning wrong post type

You have a few issues here

  • remove_filter( current_filter(), __FUNCTION__ ) is used in wrong context here for what you need to do. remove_filter() unsets the filter from the GLOBALS array once the filter has run once, so your filter is removed after the first run. This happens with spaghetti functions.

  • You should always return the default filter (or some custom default) value the make sure that something is returned as is should your conditions fail

  • get_the_title() simply uses get_post to get the post object to return the $post_title property of the object if no post object is passed to get_the_title(). So, instead of using get_the_title() which is affected by the filter, simply use get_post and from there get the post title

I would simply rewrite your filter as follow:

add_filter( 'the_title', function ( $title, $id ) 
{
    // Make sure we are not in admin, if so, return $title
    if (    is_admin() // Check if we are in admin
    )
        return $title;

    //Should work on single product pages, product archive pages, and search pages.
    if ( 
        is_post_type_archive( 'eproduct' ) ||
        is_singular ( 'eproduct' ) ||
        is_search()
    ) {

        $brand_id    = get_post_meta( $id, '_wpcf_belongs_brand-listing_id', $single = true);
        // Make sure we have a $brand_id to avoid bugs and unexpected output
        if ( $brand_id ) {
            $brand_title = get_post( $brand_id )->post_title;
            $title       = $brand_title . ' ' . $title;
        }
        // Either return title as is or our new modified title
        return $title;
    }
    // Make sure we return $title if our conditions should fail
    return $title;
}, 10, 2 );

Just an extra note, you would probably want to wrap everything in a in_the_loop() condition to only target titles in the main query loop

EDIT

I forgot to say, the code above would require at least PHP 5.4 due to direct array de-referencing. The code is also untested