See the question and my original answer on StackOverflow

The default automation peer for TextBlock (TextBlockAutomationPeer) removes the corresponding owner from the UI tree if it's part of a ControlTemplate, for some reason.

You can find the relevant code here: https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Automation/Peers/TextBlockAutomationPeer.cs,16e7fab76ffcb40a

 override protected bool IsControlElementCore()
 {
    // Return true if TextBlock is not part of a ControlTemplate
    TextBlock tb = (TextBlock)Owner;
    DependencyObject templatedParent = tb.TemplatedParent;
    return templatedParent == null || templatedParent is ContentPresenter; // If the templatedParent is a ContentPresenter, this TextBlock is generated from a DataTemplate
 }

So, to fix this, you'll have to declare the TextBlock not in a ControlTemplate, or workaround with a code like this (difficult to generalize to a whole app...):

public class LabeledComboBox : Control
{
    static LabeledComboBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledComboBox), new FrameworkPropertyMetadata(typeof(LabeledComboBox)));
    }

    // define our own peer
    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new LabeledComboBoxAutomationPeer(this);
    }

    protected class LabeledComboBoxAutomationPeer : FrameworkElementAutomationPeer
    {
        public LabeledComboBoxAutomationPeer(LabeledComboBox owner) : base(owner)
        {
        }

        // replace all TextBlockAutomationPeer by our custom peer for TextBlock
        protected override List<AutomationPeer> GetChildrenCore()
        {
            var list = base.GetChildrenCore();
            for (int i = 0; i < list.Count; i++)
            {
                var tb = list[i] as TextBlockAutomationPeer;
                if (tb != null)
                {
                    list[i] = new InteractiveTextBlockAutomationPeer((TextBlock)tb.Owner);
                }
            }
            return list;
        }
    }

    // just do the default stuff, instead of the strange TextBlockAutomationPeer implementation
    protected class InteractiveTextBlockAutomationPeer : FrameworkElementAutomationPeer
    {
        public InteractiveTextBlockAutomationPeer(TextBlock owner) : base(owner)
        {
        }

        protected override AutomationControlType GetAutomationControlTypeCore()
        {
            return AutomationControlType.Text;
        }

        protected override string GetClassNameCore()
        {
            return "TextBlock";
        }
    }
}

One other solution is to create your own TextBlock control class (deriving from TextBlock) and override OnCreateAutomationPeer to return the custom one.