After a lot of random googling, it looks like this behavior is actually "by design"
Timers using System.Threading.Timer will terminate upon an exception, no matter what you do with it, see here
There appear to be a couple of other options I can try although they use System.Timers.Timer and I'm not sure that's in NETMF and not in a position to look right now