Finally found it. In addition to the content type id, you also need to set the name of the content type:

    listItem["ContentType"] = "MyContentType";

I can't explain why it actually works though, I'd need to look at how the event receivers are resolved. I found the answer in the SaveButton webcontrol's source.