The reason seems to be that the RDLC ReportViewer operates within a separate AppDomain, and thus does not share memory with the main app.
I spent several hours refactoring my DB classes so they could be serialized and then de-serialized, all for the benefit of RDLC, only to find that after de-serializing they were not able to assign the correct DB provider because that was sitting in a static class that RDLC cannot see because it is runs in a different AppDomain.
This is the first I've really heard about AppDomains so I was not able to search for these related questions that shed light on the problem:
I found tips on forcing the report to run in the current AppDomain, which is obsolete and requires enabling CAS, but I could not get this to work in my project (I only tried for a short while):
Finally, I have decided that the correct solution is not to do code gymnastics to trick ReportViewer to work with my data - but rather to provide the report with a simple POCO that serializes and de-serializes easily, and has no complicated dependencies.
This is a good reason why DB objects should be simple and easily serializable, and the business logic should be in a separate object/wrapper on top of the DB object. These complicated "God objects" of mine have been bugging me for a while now!