A couple of notes here - first, the most direct way to translate the original snippet from c++:
into python is:
shadowNode = MDGModifier.createNode(dagMod, GroundShadowNode.id)
...where we assume that GroundShadowNode.id contains the MTypeId for the GroundShadowNode. If it doesn't, or you only know the maya node type name, createNode also takes the type name directly^:
shadowNode = MDGModifier.createNode(dagMod, "myNodeType")
Second: regarding the confusion about "api type names" and "regular type names" - what you are referring to as "api type names" might better be called MFn::Type enum names - in python (and in C++, in it's underpinnings) these actually map to integers, not strings - which you can see if you do, ie
>>> print maya.OpenMaya.MFn.kMesh
296
These are only used if the docs say a parameter needs an MFn::Type - whenever it's asking for a string, it wants what you're calling the "regular" maya node type name. And, really, this string name (or the MTypeId, for which there is a 1-to-1 relationship^^) is a much better identifier of the node type. The MFn::Type can tell which MFn* classes a node will work with, but unlike the string node types, there's not really any clear hierarchy for these types^^^, and multiple node types can map to the same MFn::Type. Basically, you should only ever use the MFn::Type if: A) the docs specifically say a function requires it, or B) you're asking the question, "Does my MFN* class work with this object?"
- Paul
^If you're curious, you can map between the MTypeId and string node name using OpenMaya.MNodeClass... thank you Dean for providing that class! =D
^^Not strictly true - it's possible for two different plugins to both provide nodes with the same name, but different MTypeId's... but if this happens, all sorts of other things will break, so you'd better hope it doesn't, and you can basically assume it won't / shouldn't. Also, reason to make sure that if you ever provide a new node type to the public, give it a name that you're reasonably sure will be unique!
^^^This is because the MFn* classes were designed to work across node-type boundaries - in programming-paradigm-speak (or if you're familiar with Java), they work more like "interfaces". In theory, you could have a MFnNamedObject class, which would work on any object that defines a name, regardless of it's node type (and might even work on things other than nodes, like Attributes) - and, in fact, MFn.kNamedObject actually exists. It's a nice idea in theory, but it's seldom used to bridge across node-hierarchy boundaries in practice, and mostly just makes it harder to understand the C++ api for newcomers, and invite the possibility for strange bugs (where some dag nodes aren't compatible with MFnDagNode, for instance).