It turns out that this is actually working correctly and I have misinterpreted the specification
When the setItem(), removeItem(), and clear() methods are called on a Storage object x that is associated with a local storage area, if the methods did something, then in every Document object whose Window object’s localStorage attribute’s Storage object is associated with the same storage area, other than x, a storage event must be fired
In other words, a storage event is fired on every window/tab except for the one that updated the localStorage
object and caused the event.
So the event was not fired because I only had one window/tab open. If I place the above code in a page and open the page in two tabs I would see the event fired in the second tab.
This answer on the problem contains more details.