Going to the thread pool and back using custom awaiters
What you are after is yielding to a different thread, which has been covered in this question. One difference is that Andrew's code implements ICriticalNotifyCompletion vs you're implementing just INotifyCompletion. I haven't found any good documentation which one to prefer and what Critical exactly means. It may mean that his code works in some weird corner case scenarios where yours might not - hard to say. Most articles state that it's optional to implement the critical interface so it may not matter.

The other difference is that Andrew's code doesn't provide an option to switch back plus he's using a struct while you are using a class (which is just a potential performance optimization)

The main conclusion was that Microsoft didn't provide this out of the box since they felt it was prone to abuse.

In general I prefer Andrew's usage pattern of TaskEx.YieldToThreadPoolThread() over your more direct await GoToThreadPool.Instance since it's slightly more readable.

So combining the two implementations one could end up with something like this:

public static class TaskEx
{
    public static YieldToThreadAwaitable YieldToThreadPool()
    {
        return new YieldToThread(null);
    }

    public static YieldToThreadAwaitable YieldToMainThread()
    {
        return new YieldToThread(Application.Current.Dispatcher.Thread);
    }

    public static YieldToThreadAwaitable YieldToThread(Thread target)
    {
        return new YieldToThread(target);
    }
}

public class YieldToThreadAwaitable : INotifyCompletion
{
    private Thread _Target;

    public YieldToThreadAwaitable(Thread target)
    {
        Target = target;
    }

    public bool IsCompleted
    {
        get { return _Target != null ? Thread.CurrentThread == _Target : Thread.CurrentThread.IsThreadPoolThread; }
    }

    public YieldToThreadAwaitable GetAwaiter()
    {
        return this;
    }

    public void GetResult() { }

    public void OnCompleted(Action continuation)
    {
        if (_Target == null)
        {
            ThreadPool.QueueUserWorkItem(o =&gt; continuation());
        }
        else
        {
            Dispatcher.FromThread(_Target).BeginInvoke(continuation);
        }
    }
}