What is a good way for the mcu to determine which hardware version it is running on?
I wouldn't use a version number programmed into the microcontroller. Unless the software is different for different board versions, but then the board version seems superfluous to me. Have as few versions of the microcontroller's software as possible, ideally just one. Each different version may cause logistic problems.  

The EEPROM code is a good idea, because it allows for lots of different board codes, but take it out of the microcontroller, in a separate device. EEPROM is expensive for large capacities (much more expensive per bit than Flash), but for a few bytes you can find them cheap. This one is only 16 cents in 100s and only needs 1 I/O line.  

A way to decrease the chance of errors is to have a different package for each board version. So have a batch of EEPROMs programmed with a version number 1 in SOT-23, the next version 2 in MSOP, etc. Then you can't have a version 1 EEPROM on a version 2 board.