Yes, a COM object tends to have strong thread affinity. Threading is not a minor implementation detail in COM. Unlike .NET, COM provides thread-safety guarantees for a COM class. COM can publish the kind of threading it supports, with "apartment" (i.e. "not thread-safe") a very common choice. COM ensures that these requirements are met without the program having to do anything to help. Marshaling a call from one thread to another so that the object is always used in a thread-safe way is automatic. In .NET code you normally have to do this yourself, using Control.BeginInvoke or Dispatcher.BeginInvoke, for example.
An automatic consequence of this is that a thread that owns one or more COM objects that's allowed to exit will automatically get these objects released. This is necessary since there is no longer a way to meet the thread safety requirement. Trying to use them anyway after this is going to bomb. There is no cure for this beyond ensuring that the thread stays alive long enough to keep servicing these objects. Similarly, you'd need to keep the UI thread alive long enough to ensure that Dispatcher.BeginInvoke can still work in .NET.
Fwiw, yes, using Marshal.ReleaseComObject() can give you plenty of fud about this. Explicit memory management has a long history of producing buggy programs, and automatic garbage collection provided the cure. GC is quite capable of getting that COM object released without your help and never gets it wrong. It just takes a bit longer to get around to it. If you know that the COM object has unusually high resource usage that warrants releasing it deterministically then you do the exact same thing you'd do for a .NET object graph that's expensive: GC.Collect() helps that along. Check this answer for the reason why Marshal.ReleaseComObject() tends to be used unnecessarily.