It is really rather best that you completely dismiss the concept of a "foreground thread". The CLR has no notion of it and does not treat the startup thread of program special in any way. It is just a "normal" thread, no different from any other thread you create with the Thread class. The notion that a "foreground thread" is important because it is doing the most visible and most "important" job is sometimes true but not always. Not in a service or a Modern UI app for example, it is worker thread that does the heavy lifting in them. It is true-ish in a console, Winforms or WPF app.
The concept is only truly valid in legacy runtime environments, like those of a C or C++ program. Their execution model dates from the 1970s, operating systems did not support threads back then. Specific in such legacy runtime environments is that the program always terminates when the startup thread ends, regardless of what other threads are running. This is not the way the CLR works, it thinks those other threads are just as important. Of course they are.
Still thinking of the concept of a "background thread" is okay. A threadpool thread is certainly backgroundish. Their IsBackground property is always true. Something you can change btw, you can simply set it to false and the CLR doesn't treat it like a background thread anymore. But you can't change its ApartmentState, it is always MTA and that makes them fundamentally unsuitable to display any user interface. In other words, you can never see them :)
The most important attribute of a background thread is that you can treat them like little soldiers that you don't mind getting killed in the line of duty. Randomly and without any notification and the expectation of no dire consequences. Pretty important that they do a non-critical job of course. It already gets iffy if, for example, you let such a thread write a file. That's going to leave a half-written file behind when the soldier gets shot. That has a knack of causing trouble later, another program reading that file is going to malfunction. A network or dbase connection is typical for a background thread. The software on the other end of the wire will detect that the connection was lost. It can't otherwise tell the difference between a hard program crash and a normal exit. Tends to end up okay, usually, such software was written to deal with that.
Long story short, only the IsBackground property matters. When a thread exits, the CLR iterates the remaining threads that are still running. If any of them have IsBackground = false then the process keeps running. If not, the CLR will unload the primary AppDomain. Which gets any soldiers shot with a rude abort.