It is best to always specify what type of join you are doing. By default it is using an inner join. An inner join will only show items that have a match in both tables. In your example, you want all the records returned from the placemark_types and zero-to-many of the records from the placemarks table that match.
To do this just use a left join as shown below. The left join always returns all the records from the left side (placemark_types) and only the matching records from the right side (placemarks). Next lets get rid of the
COUNT(*) and use COUNT(placemarks.type_id), because we don't want to count all the rows, just the ones with matches in the placemarks table. Else you would get 1 even when their where zero matches because it would still be counting the placemark_types.
SELECT COUNT(placemarks.type_id) AS type_count, placemark_types.name
LEFT JOIN placemarks ON placemark_types.id = placemarks.type_id
WHERE placemark_types.parent_id = 0
GROUP BY placemark_types.id
To understand this better, run the query without the
GROUP BY. You'll see that even when their are no entries in the placemarks table, you will get the fields from the placemark_types table and nulls for the placemarks fields. Since the
COUNT(placemarks.type_id) will not count nulls, this will give you the correct number.